<?php

class FuelController extends Controller
{
    private Fuel $fuel;
    private Document $documents;
    private Accounting $accounting;

    public function __construct()
    {
        $this->fuel = new Fuel();
        $this->documents = new Document();
        $this->accounting = new Accounting();
    }

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

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

    public function index(): void
    {
        $this->viewGuard();
        $user = Auth::user();
        $driverId = ($user['role'] ?? '') === 'driver' ? ((int) ($user['driver_id'] ?? 0) ?: -1) : null;
        $status = trim((string) ($_GET['status'] ?? '')) ?: null;
        $allocations = $this->fuel->allocations($driverId, $status);
        $transactions = $this->fuel->transactions(null, $driverId);
        $summary = $this->fuel->summary($driverId);

        $db = Database::connection();
        $loads = $db->query("SELECT loads.id, loads.load_number, loads.miles, loads.carrier_id, loads.driver_id, loads.truck_id, drivers.name driver_name, trucks.unit_number FROM loads LEFT JOIN drivers ON drivers.id=loads.driver_id LEFT JOIN trucks ON trucks.id=loads.truck_id WHERE loads.status NOT IN ('paid','cancelled') ORDER BY loads.id DESC LIMIT 300")->fetchAll();
        $carriers = $db->query("SELECT id, company_name FROM carriers WHERE status='active' ORDER BY company_name")->fetchAll();
        $drivers = $db->query("SELECT id, name, carrier_id FROM drivers WHERE status!='inactive' ORDER BY name")->fetchAll();
        $trucks = $db->query("SELECT id, unit_number, carrier_id FROM trucks WHERE status!='inactive' ORDER BY unit_number")->fetchAll();
        $accounts = $db->query("SELECT id, account_name, account_type FROM bank_accounts WHERE active=1 ORDER BY account_type='fuel_card' DESC, account_name")->fetchAll();

        $this->view('fuel/index', compact('allocations', 'transactions', 'summary', 'loads', 'carriers', 'drivers', 'trucks', 'accounts', 'driverId', 'status'));
    }

    public function storeAllocation(): void
    {
        $this->manageGuard();
        Csrf::verify();
        if (empty($_POST['driver_id']) && empty($_POST['carrier_id'])) {
            $this->flash('danger', 'Choose a driver or carrier for the fuel allocation.');
            $this->redirect('/fuel');
        }
        try {
            $id = $this->fuel->createAllocation($_POST);
            notify_roles(['owner','admin','dispatcher','accountant'], 'Fuel allowance created', 'Fuel allocation #' . $id . ' was created.', '/fuel', 'info');
            if (!empty($_POST['driver_id'])) {
                $stmt = Database::connection()->prepare("SELECT id FROM users WHERE driver_id=? AND status='active' LIMIT 1");
                $stmt->execute([(int) $_POST['driver_id']]);
                $userId = (int) ($stmt->fetchColumn() ?: 0);
                if ($userId) notify_user($userId, 'Fuel allowance available', 'A fuel allowance has been assigned to you.', '/fuel', 'success');
            }
            log_activity('fuel_allocation_created', 'Fuel allocation #' . $id . ' created');
            $this->flash('success', 'Fuel allocation created successfully.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $this->redirect('/fuel');
    }

    public function allocationStatus(): void
    {
        $this->manageGuard();
        Csrf::verify();
        $this->fuel->setAllocationStatus((int) ($_POST['id'] ?? 0), (string) ($_POST['status'] ?? 'draft'));
        $this->flash('success', 'Fuel allocation status updated.');
        $this->redirect('/fuel');
    }

    public function storeTransaction(): void
    {
        $this->viewGuard();
        Csrf::verify();
        $allocationId = (int) ($_POST['allocation_id'] ?? 0);
        $allocation = $this->fuel->findAllocation($allocationId);
        if (!$allocation) {
            $this->flash('danger', 'Fuel allocation was not found.');
            $this->redirect('/fuel');
        }
        if (!in_array($allocation['status'], ['approved','issued','partially_used'], true)) {
            $this->flash('danger', 'This fuel allocation is not available for purchases.');
            $this->redirect('/fuel');
        }
        $user = Auth::user();
        if (($user['role'] ?? '') === 'driver' && ((int) ($user['driver_id'] ?? 0) <= 0 || (int) ($allocation['driver_id'] ?? 0) !== (int) ($user['driver_id'] ?? 0))) {
            http_response_code(403);
            require app_path('Views/errors/403.php');
            exit;
        }
        try {
            $id = $this->fuel->createTransaction($_POST);
            if (!empty($_FILES['receipt']['tmp_name']) && ($_FILES['receipt']['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_OK) {
                $documentId = $this->saveReceipt($_FILES['receipt'], $id, $_POST);
                $this->fuel->attachReceipt($id, $documentId);
            }
            notify_roles(['owner','admin','dispatcher','accountant'], 'Fuel purchase submitted', 'Fuel transaction ' . $id . ' is ready for review.', '/fuel', 'warning');
            log_activity('fuel_transaction_submitted', 'Fuel transaction #' . $id . ' submitted');
            $this->flash('success', 'Fuel purchase submitted for review.');
        } catch (Throwable $exception) {
            $this->flash('danger', $exception->getMessage());
        }
        $this->redirect('/fuel');
    }

    public function transactionStatus(): void
    {
        $this->manageGuard();
        Csrf::verify();
        $id = (int) ($_POST['id'] ?? 0);
        $status = (string) ($_POST['status'] ?? 'submitted');
        $this->fuel->setTransactionStatus($id, $status);
        if (in_array($status, ['approved','posted'], true)) {
            $transaction = $this->fuel->transaction($id);
            if ($transaction && empty($transaction['expense_id'])) {
                $categoryId = $this->ensureFuelCategory();
                $expenseId = $this->accounting->createExpense([
                    'category_id' => $categoryId,
                    'vendor_id' => null,
                    'load_id' => $transaction['load_id'] ?? null,
                    'driver_id' => $transaction['driver_id'] ?? null,
                    'truck_id' => $transaction['truck_id'] ?? null,
                    'trailer_id' => null,
                    'border_crossing_id' => null,
                    'expense_date' => $transaction['transaction_date'] ?? date('Y-m-d'),
                    'amount' => $transaction['amount'] ?? 0,
                    'tax_amount' => 0,
                    'payment_method' => readable_status((string) ($transaction['allocation_method'] ?? 'fuel_card')),
                    'status' => 'approved',
                    'latitude' => $transaction['latitude'] ?? null,
                    'longitude' => $transaction['longitude'] ?? null,
                    'location_address' => $transaction['location_address'] ?? null,
                    'description' => 'Fuel purchase ' . ($transaction['transaction_number'] ?? ('#' . $id)),
                ]);
                $this->accounting->postExpense($expenseId);
                $this->fuel->linkExpense($id, $expenseId);
            }
        }
        $this->flash('success', 'Fuel transaction status updated.');
        $this->redirect('/fuel');
    }

    private function ensureFuelCategory(): int
    {
        $db = Database::connection();
        $stmt = $db->prepare("SELECT id FROM expense_categories WHERE name='Fuel' LIMIT 1");
        $stmt->execute();
        $id = (int) ($stmt->fetchColumn() ?: 0);
        if ($id) return $id;
        $db->prepare("INSERT INTO expense_categories (name, account_code, active) VALUES ('Fuel','5100',1)")->execute();
        return (int) $db->lastInsertId();
    }

    private function saveReceipt(array $file, int $transactionId, array $data): int
    {
        $original = basename((string) $file['name']);
        $extension = strtolower(pathinfo($original, PATHINFO_EXTENSION));
        $allowed = ['pdf','jpg','jpeg','png','webp','heic'];
        if (!in_array($extension, $allowed, true)) throw new RuntimeException('Unsupported fuel receipt file.');
        if (($file['size'] ?? 0) > 10 * 1024 * 1024) throw new RuntimeException('Fuel receipt cannot exceed 10 MB.');
        $folder = storage_path('uploads/fuel/' . date('Y/m'));
        if (!is_dir($folder)) mkdir($folder, 0755, true);
        $stored = bin2hex(random_bytes(16)) . '.' . $extension;
        $target = $folder . DIRECTORY_SEPARATOR . $stored;
        if (!move_uploaded_file($file['tmp_name'], $target)) throw new RuntimeException('Fuel receipt upload failed.');
        return $this->documents->create([
            'related_type' => 'fuel_transaction',
            'related_id' => $transactionId,
            'document_type' => 'Fuel Receipt',
            'file_name' => $original,
            'stored_name' => $stored,
            'file_path' => str_replace(base_path() . DIRECTORY_SEPARATOR, '', $target),
            'mime_type' => $file['type'] ?? null,
            'file_size' => $file['size'] ?? null,
            'notes' => $data['notes'] ?? null,
            'latitude' => $data['latitude'] ?? null,
            'longitude' => $data['longitude'] ?? null,
            'location_address' => $data['location_address'] ?? null,
        ]);
    }
}
