<?php
declare(strict_types=1);

namespace App\Controller\Admin;

use App\Controller\AppController;
use Cake\I18n\FrozenTime;
use App\Service\CourierPleaseService;

class ShipmentManagementController extends AppController
{
    protected $Shipments;

    public function initialize(): void
    {
        parent::initialize();

        $this->viewBuilder()
            ->setLayout('admin')
            ->setLayoutPath('Admin');

        $this->Shipments = $this->fetchTable('Shipments');
        $this->loadComponent('Flash');

        if (!$this->isAdminOrStaff()) {
            throw new \Cake\Http\Exception\ForbiddenException('Staffs only.');
        }
    }

    private function isAdminOrStaff(): bool
    {
        $id = $this->request->getAttribute('identity');
        return (bool)($id && in_array($id->get('role'), ['admin', 'staff'], true));
    }

    public function index()
    {
        $search = trim((string)$this->request->getQuery('q', ''));
        $status = trim((string)$this->request->getQuery('status', ''));
        $service = trim((string)$this->request->getQuery('service', ''));
        $airline = trim((string)$this->request->getQuery('airline', ''));
        $fromDate = trim((string)$this->request->getQuery('from_date', ''));
        $toDate = trim((string)$this->request->getQuery('to_date', ''));
        $showArchived = $this->request->getQuery('archived') === '1';

        $query = $this->Shipments->find()
            ->contain(['Bookings'])
            ->orderBy(['Shipments.created' => 'DESC']);

        $query->where(['Shipments.archived' => $showArchived ? 1 : 0]);

        if ($search !== '') {
            $query->where([
                'OR' => [
                    'Shipments.tracking_no LIKE' => '%' . $search . '%',
                    'Bookings.booking_reference LIKE' => '%' . $search . '%',
                    'Bookings.shipper_name LIKE' => '%' . $search . '%',
                    'Bookings.shipper_phone LIKE' => '%' . $search . '%',
                    'Bookings.shipper_email LIKE' => '%' . $search . '%',
                ]
            ]);
        }

        if ($status !== '') {
            $query->where(['Shipments.status' => $status]);
        }

        if ($service !== '') {
            $query->where([
                'OR' => [
                    'Bookings.mode_of_transport' => $service,
                    'Bookings.delivery_speed' => $service,
                ]
            ]);
        }

        if ($airline !== '') {
            $query->where(['Shipments.airline' => $airline]);
        }

        if ($fromDate !== '') {
            $query->where([
                'OR' => [
                    'Shipments.pickup_date >=' => $fromDate,
                    'Bookings.pickup_date >=' => $fromDate,
                ]
            ]);
        }

        if ($toDate !== '') {
            $query->where([
                'OR' => [
                    'Shipments.pickup_date <=' => $toDate,
                    'Bookings.pickup_date <=' => $toDate,
                ]
            ]);
        }

        $shipments = $query->all();

        $statusOptions = [
            'Approved',
            'Booked',
            'Picked Up',
            'Collected at Depot',
            'In Progress',
            'In Transit',
            'Out for Delivery',
            'Arrived',
            'Delivered',
            'Delayed',
            'Delivery Failed',
            'Returned',
            'Cancelled',
            'On Hold',
        ];

        $serviceOptions = [
            'Air Freight' => 'Air Freight',
            'Sea Freight' => 'Sea Freight',
            'Express' => 'Express',
            'Standard' => 'Standard',
        ];

        $airlineOptions = [
            'CourierPlease',
            'Thai Airways',
            'Qatar Airways',
            'Emirates',
            'Singapore Airlines',
            'Turkish Airlines',
            'DHL',
            'FedEx',
            'UPS',
            'TNT',
        ];

        $this->set(compact(
            'shipments',
            'statusOptions',
            'serviceOptions',
            'airlineOptions',
            'search',
            'status',
            'service',
            'airline',
            'fromDate',
            'toDate',
            'showArchived'
        ));
    }

    public function view($id = null)
    {
        $shipment = $this->Shipments->find()
            ->contain(['Bookings'])
            ->where(['Shipments.id' => $id])
            ->firstOrFail();

        $this->set(compact('shipment'));
    }

    public function edit($id = null)
    {
        $shipment = $this->Shipments->find()
            ->contain(['Bookings'])
            ->where(['Shipments.id' => $id])
            ->firstOrFail();

        $statusOptions = [
            'Approved' => 'Approved',
            'Booked' => 'Booked',
            'Picked Up' => 'Picked Up',
            'Collected at Depot' => 'Collected at Depot',
            'In Progress' => 'In Progress',
            'In Transit' => 'In Transit',
            'Out for Delivery' => 'Out for Delivery',
            'Arrived' => 'Arrived',
            'Delivered' => 'Delivered',
            'Delayed' => 'Delayed',
            'Delivery Failed' => 'Delivery Failed',
            'Returned' => 'Returned',
            'Cancelled' => 'Cancelled',
            'On Hold' => 'On Hold',
        ];

        $airlineOptions = [
            'CourierPlease' => 'CourierPlease',
            'Thai Airways' => 'Thai Airways',
            'Qatar Airways' => 'Qatar Airways',
            'Emirates' => 'Emirates',
            'Singapore Airlines' => 'Singapore Airlines',
            'Turkish Airlines' => 'Turkish Airlines',
            'DHL' => 'DHL',
            'FedEx' => 'FedEx',
            'UPS' => 'UPS',
            'TNT' => 'TNT',
        ];

        if ($this->request->is(['patch', 'post', 'put'])) {
            $data = $this->request->getData();

            $shipment = $this->Shipments->patchEntity($shipment, [
                'tracking_no' => $data['tracking_no'] ?? $shipment->tracking_no,
                'status' => $data['status'] ?? $shipment->status,
                'shipment_event' => $data['shipment_event'] ?? null,
                'airline' => $data['airline'] ?? null,
                'carrier' => $data['airline'] ?? null,
                'flight_number' => $data['flight_number'] ?? null,
                'last_location' => $data['last_location'] ?? null,
                'expected_arrived' => $data['expected_arrived'] ?? null,
                'estimated_departure' => $data['estimated_departure'] ?? null,
                'last_api_sync' => FrozenTime::now(),
            ]);

            if (!empty($data['sync_courierplease']) && !empty($shipment->tracking_no)) {
                try {
                    $service = new CourierPleaseService();
                    $result = $service->track($shipment->tracking_no);

                    if (!empty($result['success'])) {
                        $shipment->last_api_sync = FrozenTime::now();

                        $apiData = $result['data'] ?? [];

                        $shipment->shipment_event = $shipment->shipment_event ?: 'CourierPlease tracking updated';
                        $shipment->last_location = $shipment->last_location ?: 'Updated from CourierPlease';

                        if (empty($shipment->status) || $shipment->status === 'Approved') {
                            $shipment->status = 'In Transit';
                        }
                    }
                } catch (\Exception $e) {
                    $this->Flash->error('CourierPlease API sync failed: ' . $e->getMessage());
                }
            }

            if ($this->Shipments->save($shipment)) {
                $this->Flash->success('Shipment updated successfully.');
                return $this->redirect(['action' => 'view', $shipment->id]);
            }

            $this->Flash->error('Unable to update shipment.');
        }

        $this->set(compact('shipment', 'statusOptions', 'airlineOptions'));
    }

    public function archive($id = null)
    {
        $this->request->allowMethod(['post']);

        $shipment = $this->Shipments->get($id);
        $shipment->archived = 1;

        if ($this->Shipments->save($shipment)) {
            $this->Flash->success('Shipment archived successfully.');
        } else {
            $this->Flash->error('Could not archive shipment.');
        }

        return $this->redirect(['action' => 'index']);
    }

    public function unarchive($id = null)
    {
        $this->request->allowMethod(['post']);

        $shipment = $this->Shipments->get($id);
        $shipment->archived = 0;

        if ($this->Shipments->save($shipment)) {
            $this->Flash->success('Shipment restored successfully.');
        } else {
            $this->Flash->error('Could not restore shipment.');
        }

        return $this->redirect(['action' => 'index', '?' => ['archived' => 1]]);
    }

    public function delete($id = null)
    {
        $this->request->allowMethod(['post', 'delete']);

        $shipment = $this->Shipments->get($id);

        if ($this->Shipments->delete($shipment)) {
            $this->Flash->success('Shipment deleted successfully.');
        } else {
            $this->Flash->error('Could not delete shipment.');
        }

        return $this->redirect(['action' => 'index']);
    }

    public function invoice($id = null)
{
    $shipment = $this->Shipments->find()
        ->contain(['Bookings'])
        ->where(['Shipments.id' => $id])
        ->firstOrFail();

    $this->viewBuilder()->disableAutoLayout();

    $this->set(compact('shipment'));
}

public function barcodeLabel($id = null)
{
    $shipment = $this->Shipments->find()
        ->contain(['Bookings'])
        ->where(['Shipments.id' => $id])
        ->firstOrFail();

    $this->viewBuilder()->disableAutoLayout();

    $this->set(compact('shipment'));
}

public function trackingHistory($id = null)
{
    $shipment = $this->Shipments->find()
        ->contain(['Bookings'])
        ->where(['Shipments.id' => $id])
        ->firstOrFail();

    $this->set(compact('shipment'));
}

}