<?php
/**
 * TruckPmSchedules — per-truck subscription to a PM template.
 *
 * Baseline (last-service km + date) is what the cron sweep uses to compute
 * next_due_km + next_due_date. We persist those computed values on the
 * schedule row (denormalised) so the dashboard queries stay cheap.
 *
 * When a mechanic completes a PM event, the schedule's baseline rolls
 * forward to the completion km/date and next_due gets recalculated. See
 * PmEvents::markCompleted().
 */
class TruckPmSchedules extends Model
{
    public function forTruck(int $truckId): array
    {
        return (new DB())->mySelect(
            "SELECT s.c0d, s.template_id, s.baseline_km, s.baseline_date, s.next_due_km, s.next_due_date,
                    s.active, s.notes,
                    t.name AS template_name, t.kind, t.interval_km, t.interval_days,
                    t.threshold_km, t.threshold_days, t.priority
               FROM truck_pm_schedules s
               JOIN pm_templates t ON t.c0d = s.template_id
              WHERE s.truck_id = :tid AND s.deleted = 0 AND t.deleted = 0
           ORDER BY FIELD(t.priority,'critical','high','normal','low'), t.name ASC",
            [':tid' => $truckId]
        ) ?: [];
    }

    public function activeAll(): array
    {
        return (new DB())->mySelect(
            "SELECT s.c0d, s.truck_id, s.template_id, s.baseline_km, s.baseline_date,
                    s.next_due_km, s.next_due_date,
                    t.name AS template_name, t.kind, t.interval_km, t.interval_days,
                    t.threshold_km, t.threshold_days, t.priority,
                    tr.current_odometer, tr.reg_no
               FROM truck_pm_schedules s
               JOIN pm_templates t ON t.c0d = s.template_id
               JOIN trucks       tr ON tr.c0d = s.truck_id
              WHERE s.deleted = 0 AND t.deleted = 0 AND s.active = 1 AND t.active = 1
                AND tr.deleted = 0",
            []
        ) ?: [];
    }

    public function byId(int $id): array
    {
        $rs = (new DB())->mySelect(
            "SELECT s.*, t.name AS template_name, t.kind, t.interval_km, t.interval_days,
                    t.threshold_km, t.threshold_days
               FROM truck_pm_schedules s
               JOIN pm_templates t ON t.c0d = s.template_id
              WHERE s.c0d = :id AND s.deleted = 0 LIMIT 1",
            [':id' => $id]
        );
        return $rs[0] ?? [];
    }

    /**
     * Assign a template to a truck. Baseline defaults: today's odometer + today.
     */
    public function assign(int $truckId, int $templateId, array $d, int $uid): array
    {
        if ($truckId <= 0 || $templateId <= 0) return ['ok' => false, 'msg' => 'Truck and template are required.'];

        // Look up template + current truck odo
        $tpl = (new PmTemplates())->byId($templateId);
        if (!$tpl) return ['ok' => false, 'msg' => 'Template not found.'];

        $db = new DB();
        $rs = $db->mySelect("SELECT current_odometer FROM trucks WHERE c0d = :id AND deleted = 0 LIMIT 1", [':id' => $truckId]);
        if (empty($rs)) return ['ok' => false, 'msg' => 'Truck not found.'];
        $currentOdo = (int)$rs[0]['current_odometer'];

        $baselineKm   = isset($d['baseline_km'])   && $d['baseline_km']   !== '' ? (int)$d['baseline_km']   : $currentOdo;
        $baselineDate = isset($d['baseline_date']) && $d['baseline_date'] !== '' ? (string)$d['baseline_date'] : date('Y-m-d');

        [$nextKm, $nextDate] = self::computeNextDue($tpl, $baselineKm, $baselineDate);

        // Upsert — if a soft-deleted row exists, undelete it
        $ex = $db->mySelect(
            "SELECT c0d FROM truck_pm_schedules WHERE truck_id = :t AND template_id = :tp LIMIT 1",
            [':t' => $truckId, ':tp' => $templateId]
        );
        if (!empty($ex)) {
            $db->insertUpdate(
                "UPDATE truck_pm_schedules
                    SET baseline_km = :bkm, baseline_date = :bd, next_due_km = :nkm, next_due_date = :nd,
                        active = 1, deleted = 0, notes = :notes, edited_by = :uid, edited_on = NOW()
                  WHERE c0d = :id",
                [':bkm' => $baselineKm, ':bd' => $baselineDate, ':nkm' => $nextKm, ':nd' => $nextDate,
                 ':notes' => trim((string)($d['notes'] ?? '')), ':uid' => $uid, ':id' => $ex[0]['c0d']]
            );
            return ['ok' => true, 'msg' => 'Schedule re-activated.', 'id' => (int)$ex[0]['c0d']];
        }

        $r = $db->insertUpdate(
            "INSERT INTO truck_pm_schedules
                (tenant_id, truck_id, template_id, baseline_km, baseline_date, next_due_km, next_due_date, active, notes, created_by, created_on)
             VALUES
                (:tenant, :t, :tp, :bkm, :bd, :nkm, :nd, 1, :notes, :uid, NOW())",
            [
                ':tenant' => defined('DEFAULT_TENANT_ID') ? DEFAULT_TENANT_ID : 1,
                ':t'      => $truckId, ':tp' => $templateId,
                ':bkm'    => $baselineKm, ':bd' => $baselineDate,
                ':nkm'    => $nextKm,     ':nd' => $nextDate,
                ':notes'  => trim((string)($d['notes'] ?? '')),
                ':uid'    => $uid,
            ]
        );
        return ['ok' => $r['success'] > 0, 'msg' => 'Schedule created.', 'id' => (int)$r['last_id']];
    }

    public function updateBaseline(int $scheduleId, int $km, string $date, int $uid): void
    {
        $s = $this->byId($scheduleId);
        if (!$s) return;
        [$nextKm, $nextDate] = self::computeNextDue($s, $km, $date);
        (new DB())->insertUpdate(
            "UPDATE truck_pm_schedules
                SET baseline_km = :bkm, baseline_date = :bd, next_due_km = :nkm, next_due_date = :nd,
                    edited_by = :uid, edited_on = NOW()
              WHERE c0d = :id",
            [':bkm' => $km, ':bd' => $date, ':nkm' => $nextKm, ':nd' => $nextDate, ':uid' => $uid, ':id' => $scheduleId]
        );
    }

    public function softDelete(int $id, int $uid): void
    {
        (new DB())->insertUpdate(
            "UPDATE truck_pm_schedules SET deleted = 1, active = 0, edited_by = :uid, edited_on = NOW() WHERE c0d = :id",
            [':uid' => $uid, ':id' => $id]
        );
    }

    /**
     * Given a template row + baseline, return [next_due_km, next_due_date].
     * Either or both can be NULL depending on template config.
     */
    public static function computeNextDue(array $tpl, ?int $baselineKm, ?string $baselineDate): array
    {
        $ikm   = (int)($tpl['interval_km']   ?? 0);
        $idays = (int)($tpl['interval_days'] ?? 0);
        $nextKm   = ($ikm   > 0 && $baselineKm   !== null) ? ($baselineKm + $ikm) : null;
        $nextDate = ($idays > 0 && $baselineDate)          ? date('Y-m-d', strtotime($baselineDate . ' +' . $idays . ' days')) : null;
        return [$nextKm, $nextDate];
    }
}
