<?php
declare(strict_types=1);

namespace App\Controller\Admin;

use App\Controller\AppController;
use Cake\I18n\FrozenTime;
use Cake\Mailer\Mailer;

class BookingManagementController extends AppController
{
    protected $Bookings;

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

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

        $this->Bookings = $this->fetchTable('Bookings');
        $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', ''));
        $selectedStatus = trim((string)$this->request->getQuery('status', ''));
        $selectedPickupDate = trim((string)$this->request->getQuery('pickup_date', ''));
        $showArchived = $this->request->getQuery('archived') === '1';

        $bookingsQuery = $this->Bookings->find()
            ->orderBy(['created' => 'DESC']);

        if ($showArchived) {
            $bookingsQuery->where(['archived' => 1]);
        } else {
            $bookingsQuery->where(['archived' => 0]);
        }

        if ($search !== '') {
            $bookingsQuery->where([
                'OR' => [
                    'booking_reference LIKE' => '%' . $search . '%',
                    'shipper_name LIKE' => '%' . $search . '%',
                    'receiver_name LIKE' => '%' . $search . '%',
                    'shipper_address LIKE' => '%' . $search . '%',
                    'delivery_address LIKE' => '%' . $search . '%',
                    'shipper_phone LIKE' => '%' . $search . '%',
                    'receiver_phone LIKE' => '%' . $search . '%',
                ]
            ]);
        }

        if ($selectedStatus !== '') {
            $bookingsQuery->where(['status' => $selectedStatus]);
        }

        if ($selectedPickupDate !== '') {
            $bookingsQuery->where(['pickup_date' => $selectedPickupDate]);
        }

        $bookings = $bookingsQuery->all();

        $statusOptions = [
            'Pending',
            'Confirmed',
            'Picked Up',
            'Collected at Depot',
            'In Transit',
            'Out for Delivery',
            'Delivered',
            'Delivery Failed',
            'Returned',
            'Cancelled',
            'On Hold',
        ];

        $this->set(compact(
            'bookings',
            'statusOptions',
            'selectedStatus',
            'selectedPickupDate',
            'search',
            'showArchived'
        ));
    }

    public function view($id = null)
    {
        $booking = $this->Bookings->find()
            ->where([
                'id' => $id,
            ])
            ->firstOrFail();

        $statusOptions = [
            'Pending',
            'Confirmed',
            'Picked Up',
            'Collected at Depot',
            'In Transit',
            'Out for Delivery',
            'Delivered',
            'Delivery Failed',
            'Returned',
            'Cancelled',
            'On Hold',
        ];

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

            if (!empty($data['status'])) {
                $data['last_status_update'] = FrozenTime::now();
            }

            if (($data['collection_method'] ?? 'Drop Off') === 'Drop Off') {
        $data['collection_method'] = 'Drop Off';
        $data['dropoff_location'] = '1011 Sydney Road, Coburg North, Victoria 3047';
        $data['dropoff_map_link'] = 'https://www.google.com/maps?q=1011+Sydney+Road,+Coburg+North,+Victoria+3047';
        $data['dropoff_note'] = 'Please drop your parcel between 8:00 AM and 4:00 PM.';
        $data['pickup_date'] = null;
        $data['pickup_time'] = null;
    } else {
        $data['collection_method'] = 'Pickup';
        $data['dropoff_location'] = null;
        $data['dropoff_map_link'] = null;
        $data['dropoff_note'] = null;
    }

            $booking = $this->Bookings->patchEntity($booking, $data);

            if ($this->Bookings->save($booking)) {
                $this->Flash->success('Booking updated successfully.');
                return $this->redirect([
                    'prefix' => 'Admin',
                    'controller' => 'BookingManagement',
                    'action' => 'view',
                    $booking->id
                ]);
            }

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

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

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

        $booking = $this->Bookings->get($id);
        $booking->archived = 1;
        $booking->last_status_update = FrozenTime::now();
        $booking->status = 'Archived';

        if ($this->Bookings->save($booking)) {
            $this->Flash->success('Booking archived successfully.');
        } else {
            $this->Flash->error('Could not archive booking.');
        }

        return $this->redirect([
            'prefix' => 'Admin',
            'controller' => 'BookingManagement',
            'action' => 'index'
        ]);
    }

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

        $booking = $this->Bookings->get($id);
        $booking->archived = 0;
        $booking->last_status_update = FrozenTime::now();

        if ($booking->status === 'Archived') {
            $booking->status = 'Pending';
        }

        if ($this->Bookings->save($booking)) {
            $this->Flash->success('Booking moved back to recent bookings.');
        } else {
            $this->Flash->error('Could not restore booking.');
        }

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

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

        $booking = $this->Bookings->get($id);

        if ($this->Bookings->delete($booking)) {
            $this->Flash->success('Booking deleted successfully.');
        } else {
            $this->Flash->error('Could not delete booking.');
        }

        return $this->redirect([
            'prefix' => 'Admin',
            'controller' => 'BookingManagement',
            'action' => 'index'
        ]);
    }

    public function reject($id = null)
    {
        $this->request->allowMethod(['post','ajax']);
        if (!$id) {
            $id = $this->request->getData('booking_id');
        }
        $bookingId = $id ?: $this->request->getData('booking_id');

        if (!$bookingId) {
            return $this->response
                ->withStatus(400)
                ->withType('application/json')
                ->withStringBody(json_encode(['success' => false, 'message' => 'Invalid ID']));
        }
        $booking = $this->Bookings->get($bookingId);


        $reason = $this->request->getData('reason');

        $booking->last_status_update = FrozenTime::now();
        $booking->status = 'Rejected';

        $mailer = new Mailer('default');
        $mailer
            ->setEmailFormat('both')
            ->setTo($booking->shipper_email)
            ->setSubject('Regarding your booking request: ' . $booking->booking_reference)
            ->viewBuilder()
            ->setTemplate('reject_booking');

        $mailer->setViewVars([
            'name' => $booking->shipper_name,
            'email' => $booking->shipper_email,
            'booking_ref' => $booking->booking_reference,
            'reason' => $reason,
        ]);

        $success = false;
        $message = '';

        if ($mailer->deliver()) {
            if ($this->Bookings->save($booking)) {
                $success = true;
                $message = 'Booking rejected successfully.';
            } else {
                $message = 'Could not update booking status in database.';
            }
        } else {
            $message = 'Failed to send the rejection email.';
        }
        $responseData = [
            'success' => $success,
            'message' => $message
        ];

        return $this->response
            ->withType('application/json')
            ->withStringBody(json_encode($responseData));
    }

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

        $booking = $this->Bookings->get($id);
        $booking->last_status_update = FrozenTime::now();
        $booking->status = 'Approved';

        if ($this->Bookings->save($booking)) {
            $this->Flash->success('Booking approved successfully.');
        } else {
            $this->Flash->error('Could not approve booking.');
        }

        return $this->redirect([
            'prefix' => 'Admin',
            'controller' => 'BookingManagement',
            'action' => 'index'
        ]);
    }
}
