<?php

class HoursOfServiceController extends Controller
{
    private HoursOfService $hos;

    public function __construct()
    {
        $this->hos = new HoursOfService();
    }

    private function viewGuard(): void
    {
        Auth::requireLogin();
        if (!can('hos.view') && !can('hos.driver')) {
            http_response_code(403);
            require app_path('Views/errors/403.php');
            exit;
        }
    }

    private function manageGuard(): void
    {
        Auth::requireLogin();
        if (!can('hos.manage')) {
            http_response_code(403);
            require app_path('Views/errors/403.php');
            exit;
        }
    }

    private function resolvedDriverId(): int
    {
        $user = Auth::user();
        if (($user['role'] ?? '') === 'driver') {
            $driverId = (int) ($user['driver_id'] ?? 0);
            if ($driverId <= 0) throw new RuntimeException('This account is not linked to a driver profile.');
            return $driverId;
        }
        $driverId = (int) ($_GET['driver_id'] ?? $_POST['driver_id'] ?? 0);
        if ($driverId <= 0) throw new RuntimeException('Choose a driver.');
        return $driverId;
    }

    private function ensureDriverAccess(int $driverId): void
    {
        $user = Auth::user();
        if (($user['role'] ?? '') === 'driver' && (int) ($user['driver_id'] ?? 0) !== $driverId) {
            http_response_code(403);
            require app_path('Views/errors/403.php');
            exit;
        }
        if (($user['role'] ?? '') === 'carrier') {
            $stmt = Database::connection()->prepare('SELECT COUNT(*) FROM drivers WHERE id=? AND carrier_id=?');
            $stmt->execute([$driverId, (int) ($user['carrier_id'] ?? 0)]);
            if (!(int) $stmt->fetchColumn()) {
                http_response_code(403);
                require app_path('Views/errors/403.php');
                exit;
            }
        }
    }

    public function index(): void
    {
        $this->viewGuard();
        if ((Auth::user()['role'] ?? '') === 'driver') {
            $this->redirect('/hos/driver');
        }
        $user = Auth::user();
        $carrierId = ($user['role'] ?? '') === 'carrier' ? ((int) ($user['carrier_id'] ?? 0) ?: -1) : null;
        $drivers = $this->hos->overview($carrierId);
        $pendingEdits = ($user['role'] ?? '') === 'carrier' ? [] : $this->hos->editRequests(null, 'pending');
        $summary = [
            'driving' => 0,
            'near_limit' => 0,
            'violations' => 0,
            'pending_edits' => count($pendingEdits),
        ];
        foreach ($drivers as $driver) {
            $clocks = $driver['clocks'];
            if (($clocks['current_status'] ?? '') === 'driving') $summary['driving']++;
            if (($clocks['drive_remaining'] ?? 9999) <= 120 || ($clocks['shift_remaining'] ?? 9999) <= 120 || ($clocks['cycle_remaining'] ?? 9999) <= 300) $summary['near_limit']++;
            if (!empty($clocks['violations'])) $summary['violations']++;
        }
        $pageTitle = 'Driver Logbooks & HOS';
        $this->view('hos/index', compact('drivers', 'pendingEdits', 'summary', 'pageTitle'));
    }

    public function driver(): void
    {
        $this->viewGuard();
        try {
            $driverId = $this->resolvedDriverId();
            $this->ensureDriverAccess($driverId);
            $date = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['date'] ?? '')) ? (string) $_GET['date'] : date('Y-m-d');
            $profile = $this->hos->profileForDriver($driverId);
            $clocks = $this->hos->clockSummary($driverId);
            $daily = $this->hos->dailySummary($driverId, $date);
            $events = $this->hos->eventsForDay($driverId, $date);
            $logs = $this->hos->logs($driverId, $clocks['rule_set'] === 'us_property' ? 8 : 15, $date);
            $assignments = $this->hos->assignments($driverId);
            $pendingEdits = $this->hos->editRequests($driverId, 'pending');
            $current = $this->hos->currentEvent($driverId);
            $isOwnDriver = (Auth::user()['role'] ?? '') === 'driver';
            $pageTitle = $profile['driver_name'] . ' · Logbook';
            $this->view('hos/driver', compact('driverId', 'date', 'profile', 'clocks', 'daily', 'events', 'logs', 'assignments', 'pendingEdits', 'current', 'isOwnDriver', 'pageTitle'));
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
            $this->redirect('/hos');
        }
    }

    public function profile(): void
    {
        $this->manageGuard();
        try {
            $driverId = $this->resolvedDriverId();
            $profile = $this->hos->profileForDriver($driverId);
            $pageTitle = 'HOS Profile · ' . $profile['driver_name'];
            $this->view('hos/profile', compact('driverId', 'profile', 'pageTitle'));
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
            $this->redirect('/hos');
        }
    }

    public function saveProfile(): void
    {
        $this->manageGuard();
        Csrf::verify();
        try {
            $driverId = $this->resolvedDriverId();
            $this->hos->saveProfile($driverId, $_POST);
            log_activity('hos_profile_updated', 'HOS profile updated for driver #' . $driverId);
            $this->flash('success', 'Driver HOS profile updated.');
            $this->redirect('/hos/driver?driver_id=' . $driverId);
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
            $this->back();
        }
    }

    public function storeEvent(): void
    {
        $this->viewGuard();
        Csrf::verify();
        try {
            $driverId = $this->resolvedDriverId();
            $this->ensureDriverAccess($driverId);
            if ((Auth::user()['role'] ?? '') !== 'driver' && !can('hos.manage')) {
                throw new RuntimeException('You do not have permission to add driver duty events.');
            }
            $eventId = $this->hos->storeEvent($driverId, $_POST);
            $statusLabel = hos_status_label((string) ($_POST['duty_status'] ?? ''), (string) ($_POST['special_status'] ?? ''));
            log_activity('hos_event_created', 'HOS event #' . $eventId . ' · ' . $statusLabel . ' · driver #' . $driverId);
            if (!empty($this->hos->clockSummary($driverId)['violations'])) {
                notify_roles(['owner','admin','dispatcher'], 'HOS violation alert', 'A driver log has reached or exceeded a configured limit.', '/hos/driver?driver_id=' . $driverId, 'danger');
            }
            $this->flash('success', $statusLabel . ' started.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $date = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_POST['log_date'] ?? '')) ? (string) $_POST['log_date'] : date('Y-m-d');
        $driverPart = (Auth::user()['role'] ?? '') === 'driver' ? '' : '?driver_id=' . (int) ($_POST['driver_id'] ?? 0) . '&date=' . $date;
        if ($driverPart === '') $driverPart = '?date=' . $date;
        $this->redirect('/hos/driver' . $driverPart);
    }

    public function updateLog(): void
    {
        $this->viewGuard();
        Csrf::verify();
        try {
            $driverId = $this->resolvedDriverId();
            $this->ensureDriverAccess($driverId);
            $date = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_POST['log_date'] ?? '')) ? (string) $_POST['log_date'] : date('Y-m-d');
            $this->hos->updateDailyLog($driverId, $date, $_POST);
            log_activity('hos_log_updated', 'Daily HOS details updated for driver #' . $driverId . ' on ' . $date);
            $this->flash('success', 'Daily log details saved.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $this->back();
    }

    public function certify(): void
    {
        $this->viewGuard();
        Csrf::verify();
        try {
            $driverId = $this->resolvedDriverId();
            $this->ensureDriverAccess($driverId);
            if ((Auth::user()['role'] ?? '') !== 'driver') {
                throw new RuntimeException('The driver must certify their own record of duty status.');
            }
            $date = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_POST['log_date'] ?? '')) ? (string) $_POST['log_date'] : date('Y-m-d');
            $this->hos->certify($driverId, $date, (string) ($_POST['certification_name'] ?? ''));
            log_activity('hos_log_certified', 'Driver #' . $driverId . ' certified HOS log for ' . $date);
            $this->flash('success', 'Log certified successfully.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $this->back();
    }

    public function requestEdit(): void
    {
        $this->viewGuard();
        Csrf::verify();
        try {
            $driverId = $this->resolvedDriverId();
            $this->ensureDriverAccess($driverId);
            if ((Auth::user()['role'] ?? '') !== 'driver' && !can('hos.manage')) {
                throw new RuntimeException('You do not have permission to request duty-event corrections.');
            }
            $id = $this->hos->createEditRequest((int) ($_POST['event_id'] ?? 0), $driverId, $_POST);
            notify_roles(['owner','admin','dispatcher'], 'HOS edit awaiting review', 'Driver log edit request #' . $id . ' requires review.', '/hos', 'warning');
            log_activity('hos_edit_requested', 'HOS edit request #' . $id . ' submitted');
            $this->flash('success', 'Edit request submitted. The original event remains preserved until review.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $this->back();
    }

    public function reviewEdit(): void
    {
        $this->manageGuard();
        Csrf::verify();
        try {
            $requestId = (int) ($_POST['request_id'] ?? 0);
            $decision = (string) ($_POST['decision'] ?? 'rejected');
            $this->hos->reviewEdit($requestId, $decision, (string) ($_POST['review_notes'] ?? ''));
            log_activity('hos_edit_reviewed', 'HOS edit request #' . $requestId . ' ' . $decision);
            $this->flash('success', 'Edit request ' . $decision . '.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $this->back();
    }

    public function inspection(): void
    {
        $this->viewGuard();
        try {
            $driverId = $this->resolvedDriverId();
            $this->ensureDriverAccess($driverId);
            $profile = $this->hos->profileForDriver($driverId);
            $endDate = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['end_date'] ?? '')) ? (string) $_GET['end_date'] : date('Y-m-d');
            $days = str_starts_with((string) $profile['default_rule_set'], 'canada') ? 15 : 8;
            $logs = $this->hos->logs($driverId, $days, $endDate);
            $pageTitle = 'Inspection Logbook · ' . $profile['driver_name'];
            $this->view('hos/inspection', compact('driverId', 'profile', 'endDate', 'days', 'logs', 'pageTitle'));
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
            $this->redirect('/hos');
        }
    }

    public function pdf(): void
    {
        $this->viewGuard();
        $driverId = $this->resolvedDriverId();
        $this->ensureDriverAccess($driverId);
        $date = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['date'] ?? '')) ? (string) $_GET['date'] : date('Y-m-d');
        $profile = $this->hos->profileForDriver($driverId);
        $daily = $this->hos->dailySummary($driverId, $date);
        $log = $daily['log'];

        $pdf = new SimplePdf();
        $logo = public_path('assets/images/fleetlume-mark.png');
        $pdf->image($logo, 42, 716, 52, 52);
        $pdf->text(105, 748, 'FleetLume Driver Record of Duty Status', 16, true);
        $pdf->text(105, 728, 'Operational logbook report · ' . $date, 10);
        $pdf->line(42, 705, 570, 705, 1.2);

        $pdf->text(42, 682, 'Driver', 8, true); $pdf->text(100, 682, (string) $profile['driver_name'], 10);
        $pdf->text(320, 682, 'Rule set', 8, true); $pdf->text(380, 682, hos_rule_label((string) ($log['rule_set'] ?? $profile['default_rule_set'])), 9);
        $pdf->text(42, 663, 'Carrier', 8, true); $pdf->text(100, 663, (string) ($profile['carrier_name'] ?? '—'), 9);
        $pdf->text(320, 663, 'Cycle', 8, true); $pdf->text(380, 663, (string) ($log['cycle_code'] ?? '—'), 9);
        $pdf->text(42, 644, 'Vehicle', 8, true); $pdf->text(100, 644, (string) ($log['vehicle_numbers'] ?? '—'), 9);
        $pdf->text(320, 644, 'Trailer', 8, true); $pdf->text(380, 644, (string) ($log['trailer_numbers'] ?? '—'), 9);
        $pdf->text(42, 625, 'Shipping docs', 8, true); $pdf->text(120, 625, (string) ($log['shipping_documents'] ?? '—'), 9);

        $graphX = 56; $graphY = 470; $graphW = 500; $rowH = 28;
        $labels = ['Off Duty','Sleeper','Driving','On Duty'];
        for ($r=0; $r<4; $r++) {
            $y = $graphY + (3-$r)*$rowH;
            $pdf->text(8, $y + 8, $labels[$r], 7);
            $pdf->line($graphX, $y, $graphX+$graphW, $y, .5);
        }
        $pdf->line($graphX, $graphY+4*$rowH, $graphX+$graphW, $graphY+4*$rowH, .5);
        for ($h=0; $h<=24; $h++) {
            $x=$graphX+($graphW/24)*$h;
            $pdf->line($x,$graphY,$x,$graphY+4*$rowH,$h%6===0?.7:.2);
            if($h<24 && $h%2===0)$pdf->text($x+1,$graphY+4*$rowH+7,(string)$h,6);
        }
        $rowMap=['off_duty'=>3,'sleeper_berth'=>2,'driving'=>1,'on_duty'=>0];
        $previousY=null;
        foreach ($daily['segments'] as $segment) {
            $startTs=strtotime($segment['start']);$endTs=strtotime($segment['end']);
            $dayStart=strtotime((string)($daily['start_at'] ?? ($date.' 00:00:00')));
            $startMin=max(0,($startTs-$dayStart)/60);$endMin=min(1440,($endTs-$dayStart)/60);
            $x1=$graphX+$graphW*($startMin/1440);$x2=$graphX+$graphW*($endMin/1440);
            $row=$rowMap[$segment['duty_status']]??3;$y=$graphY+$row*$rowH+$rowH/2;
            if($previousY!==null)$pdf->line($x1,$previousY,$x1,$y,1.4);
            $pdf->line($x1,$y,$x2,$y,1.8);$previousY=$y;
        }

        $pdf->text(42, 440, 'Daily totals', 11, true);
        $pdf->rect(42, 370, 528, 56, true, .96);
        $totals = [
            'Off duty'=>hos_minutes($daily['totals']['off_duty']),
            'Sleeper'=>hos_minutes($daily['totals']['sleeper_berth']),
            'Driving'=>hos_minutes($daily['totals']['driving']),
            'On duty'=>hos_minutes($daily['totals']['on_duty']),
        ];
        $i=0; foreach($totals as $label=>$value){$x=55+$i*128;$pdf->text($x,405,$label,8,true);$pdf->text($x,384,$value,15,true);$i++;}
        $pdf->text(42, 345, 'Certification status', 9, true);
        $pdf->text(145, 345, readable_status((string) ($log['status'] ?? 'draft')) . (!empty($log['certification_name']) ? ' · ' . $log['certification_name'] : ''), 9);
        $pdf->text(42, 323, 'Exceptions / declarations', 9, true);
        $exceptions = json_decode((string) ($log['exceptions'] ?? ''), true) ?: [];
        $pdf->wrappedText(160, 323, $exceptions ? implode(', ', array_map('readable_status', $exceptions)) : 'None recorded', 400, 9, 12, false, 3);
        $pdf->text(42, 280, 'Violations / warnings', 9, true);
        $pdf->wrappedText(160, 280, $daily['violations'] ? implode('; ', $daily['violations']) : 'No automated warnings for this day', 400, 9, 12, false, 4);
        $pdf->line(42, 74, 570, 74, .5);
        $pdf->wrappedText(42, 60, 'This report is an operational record generated by FleetLume. It is not proof that FleetLume is a registered or certified ELD. Verify records against the applicable carrier policy and regulatory requirements.', 528, 7, 9, false, 3);

        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename="hos-' . preg_replace('/[^a-z0-9-]+/i','-',strtolower((string)$profile['driver_name'])) . '-' . $date . '.pdf"');
        echo $pdf->output();
        exit;
    }
}
