<?php

require_once __DIR__ . '/../../core/bootstrap.php';
require_once __DIR__ . '/../../core/status_engine.php';
require_once __DIR__ . '/../../core/penalty.php';
require_once __DIR__ . '/../../core/reward.php';

/* ----------------------------------------------------------
   METHOD CHECK
---------------------------------------------------------- */

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    json_response(false, 'Invalid request method.', [], 405);
}

/* ----------------------------------------------------------
   AUTHENTICATE
---------------------------------------------------------- */

$user = authenticate($pdo);

if (!in_array($user['role'], ['sp_admin', 'artisan'], true)) {
    json_response(false, 'Access denied. SP role required.', [], 403);
}

$sp_company_id = (int)$user['company_id'];
$rsp_id        = (int)$user['rsp_id'];

if (!$sp_company_id) {
    json_response(false, 'Service provider not linked.', [], 403);
}

/* ----------------------------------------------------------
   INPUT VALIDATION
---------------------------------------------------------- */

$input = json_decode(file_get_contents('php://input'), true);

if (!is_array($input) || !isset($input['breakdown_id'], $input['new_status'])) {
    json_response(false, 'Breakdown ID and new status required.', [], 400);
}

$breakdown_id = (int)$input['breakdown_id'];
$new_status   = trim((string)$input['new_status']);

/* ----------------------------------------------------------
   FETCH BREAKDOWN + TENANT VALIDATION
---------------------------------------------------------- */

$stmt = $pdo->prepare("
    SELECT
        b.id,
        b.status,
        b.start_odo,
        b.end_odo,
        b.travel_distance_km,
        b.billable_distance_km,
        b.allocated_at,
        b.broadcast_started_at,
        b.broadcast_cycle,
        b.started_at,
        b.arrived_at,
        b.completed_at,
        b.accepted_company_id,
        c.rsp_id
    FROM breakdowns b
    JOIN companies c ON c.id = b.fleet_company_id
    WHERE b.id = ?
      AND b.accepted_company_id = ?
    LIMIT 1
");

$stmt->execute([$breakdown_id, $sp_company_id]);
$breakdown = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$breakdown) {
    json_response(false, 'Breakdown not found or not assigned.', [], 404);
}

/* ----------------------------------------------------------
   TENANT ISOLATION
---------------------------------------------------------- */

if ((int)$breakdown['rsp_id'] !== $rsp_id) {
    json_response(false, 'Access denied.', [], 403);
}

/* ----------------------------------------------------------
   CENTRAL STATUS VALIDATION
---------------------------------------------------------- */

validate_status_transition($breakdown, $new_status);

/* ----------------------------------------------------------
   TRANSACTION
---------------------------------------------------------- */

$pdo->beginTransaction();

try {

    $update_fields = [];
    $params = [];

    /* ======================================================
       ENROUTE
    ====================================================== */

    if ($new_status === 'enroute') {

        if (!isset($input['start_odo'])) {
            json_response(false, 'start_odo required.', [], 400);
        }

        $start_odo = (int)$input['start_odo'];

        if ($start_odo <= 0) {
            json_response(false, 'Invalid start_odo.', [], 400);
        }

        /* Penalty: Late dispatch */

        if (!empty($breakdown['allocated_at'])) {

            $delay = (time() - strtotime($breakdown['allocated_at'])) / 60;

            if ($delay > 10) {

                apply_penalty(
                    $pdo,
                    $sp_company_id,
                    $breakdown_id,
                    'Late dispatch (allocated→enroute)',
                    1
                );
            }
        }

        $update_fields[] = "started_at = NOW()";
        $update_fields[] = "start_odo = ?";

        $params[] = $start_odo;
    }

    /* ======================================================
       ARRIVED
    ====================================================== */

    if ($new_status === 'arrived') {

        if (!isset($input['end_odo'])) {
            json_response(false, 'end_odo required.', [], 400);
        }

        $end_odo = (int)$input['end_odo'];

        if (
            $end_odo <= 0 ||
            $breakdown['start_odo'] === null ||
            $end_odo < $breakdown['start_odo']
        ) {
            json_response(false, 'Invalid ODO values.', [], 400);
        }

        $travel_distance   = $end_odo - (int)$breakdown['start_odo'];
        $billable_distance = $travel_distance * 2;

        /* Tier SLA calculation based on broadcast_cycle */

        if (!empty($breakdown['started_at'])) {

            $travel_time = (time() - strtotime($breakdown['started_at'])) / 60;

            $tier_limit = ((int)$breakdown['broadcast_cycle']) * 30;

            if ($travel_time > $tier_limit) {

                apply_penalty(
                    $pdo,
                    $sp_company_id,
                    $breakdown_id,
                    'Exceeded travel SLA',
                    1
                );
            }
        }

        $update_fields[] = "arrived_at = NOW()";
        $update_fields[] = "end_odo = ?";
        $update_fields[] = "travel_distance_km = ?";
        $update_fields[] = "billable_distance_km = ?";

        $params[] = $end_odo;
        $params[] = $travel_distance;
        $params[] = $billable_distance;
    }

    /* ======================================================
       IN PROGRESS
    ====================================================== */

    if ($new_status === 'in_progress') {

        $update_fields[] = "started_at = NOW()";
    }

    /* ======================================================
       COMPLETED
    ====================================================== */

    if ($new_status === 'completed') {

        if (empty($input['completion_notes'])) {
            json_response(false, 'completion_notes required.', [], 400);
        }

        $notes = trim($input['completion_notes']);

        $update_fields[] = "completed_at = NOW()";
        $update_fields[] = "completion_notes = ?";

        $params[] = $notes;

        /* ---------------- SIGNATURE ---------------- */

        if (!empty($input['signature_base64'])) {

            $base64 = $input['signature_base64'];

            if (!preg_match('/^data:image\/png;base64,/', $base64)) {
                json_response(false, 'Invalid signature format.', [], 400);
            }

            $binary = base64_decode(
                str_replace('data:image/png;base64,', '', $base64)
            );

            if ($binary === false) {
                json_response(false, 'Invalid base64 data.', [], 400);
            }

            $dir = __DIR__ . '/../../uploads/signatures';

            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }

            $filename = "signature_breakdown_{$breakdown_id}.png";
            $path = $dir . '/' . $filename;

            if (!file_put_contents($path, $binary)) {
                json_response(false, 'Signature save failed.', [], 500);
            }

            $update_fields[] = "signature_path = ?";
            $params[] = "uploads/signatures/" . $filename;
        }

        /* Reward evaluation */

        evaluate_rewards(
            $pdo,
            $sp_company_id,
            $breakdown_id,
            $breakdown
        );
    }

    /* ----------------------------------------------------------
       APPLY STATUS UPDATE
    ---------------------------------------------------------- */

    $update_fields[] = "status = ?";

    $params[] = $new_status;
    $params[] = $breakdown_id;

    $sql = "UPDATE breakdowns SET " . implode(', ', $update_fields) . " WHERE id = ?";

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);

    $pdo->commit();

    json_response(true, 'Status updated successfully.', [
        'previous_status' => $breakdown['status'],
        'new_status'      => $new_status
    ]);

} catch (Throwable $e) {

    $pdo->rollBack();

    json_response(false, 'Status update failed.', [], 500);
}