<?php
/**
 * ServiceReports — Slice 8S-8
 *
 * Monthly compliance PDF per Service Contract. Satisfies both:
 *   (a) SLA clause in TZ tenders ("Monthly PM report format: PDF within 5 working days")
 *   (b) Invoice backup — attached to the consumption invoice as evidence.
 *
 * Sections:
 *   0. Cover (contract + customer + period)
 *   1. Contract terms summary
 *   2. PMs executed
 *   3. Callouts (with SLA compliance)
 *   4. SLA compliance summary per category
 *   5. Parts consumed
 *   6. Cost summary (mirrors the consumption calc)
 *   7. Notes + sign-off
 */
class ServiceReports extends Model
{
    /**
     * Build the PDF for a contract-month. Returns the RsPdfReport (call ->Output(...) yourself).
     */
    public function build(int $contractId, int $year, int $month): RsPdfReport
    {
        if (!class_exists('ServiceContracts')) require_once ROOT . '/app/models/ServiceContracts.php';
        if (!class_exists('FPDF'))             require_once ROOT . '/core/FPDF.php';
        if (!defined('FPDF_FONTPATH'))         define('FPDF_FONTPATH', ROOT . '/fonts/fpdf/');
        if (!class_exists('RsPdfReport'))      require_once ROOT . '/app/models/RsPdfReport.php';

        $sc = new ServiceContracts();
        $c  = $sc->find($contractId);
        if (empty($c)) throw new RuntimeException('Contract not found.');

        $db          = new DB();
        $periodStart = sprintf('%04d-%02d-01', $year, $month);
        $periodEnd   = date('Y-m-t', strtotime($periodStart));
        $periodLabel = date('F Y', strtotime($periodStart));

        $pdf = new RsPdfReport('P', 'mm', 'A4');
        $pdf->setReportMeta(
            'Monthly Service Report',
            $c['contract_no'] . '  ·  ' . $c['customer_name'] . '  ·  ' . $periodLabel
        );
        $pdf->AliasNbPages();
        $pdf->AddPage();

        /* ── Section 0 · Contract summary ─────────────────────────────── */
        $this->sectionHeader($pdf, 'Contract summary');
        $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
        $rows = [
            ['Contract',       $c['contract_no']],
            ['Customer',       $c['customer_name']],
            ['Project',        (string)($c['project_no'] ?? '') . ' ' . (string)($c['project_name'] ?? '')],
            ['Period',         $periodLabel . ' (' . $periodStart . ' → ' . $periodEnd . ')'],
            ['Cadence',        ucwords(strtolower(str_replace('_', ' ', (string)$c['invoice_cadence'])))],
            ['Spare policy',   ucwords(strtolower(str_replace('_', ' ', (string)$c['spare_policy'])))],
            ['Currency',       (string)$c['currency']],
            ['Monthly retainer',$c['monthly_retainer'] !== null ? number_format((float)$c['monthly_retainer']) : '—'],
            ['Labour rate/hr', $c['labour_rate_per_hr'] !== null ? number_format((float)$c['labour_rate_per_hr']) : '—'],
            ['Callout fee',    $c['callout_fee'] !== null ? number_format((float)$c['callout_fee']) : '—'],
            ['Parts markup',   $c['parts_markup_pct'] !== null ? number_format((float)$c['parts_markup_pct'], 1) . ' %' : '—'],
            ['Free callouts/month', (string)((int)($c['free_callouts_per_month'] ?? 0))],
        ];
        foreach ($rows as $r) {
            $pdf->SetTextColor(100, 116, 139);
            $pdf->Cell(50, 5.5, $this->safe($r[0]), 0, 0, 'L');
            $pdf->SetTextColor(51, 65, 85);
            $pdf->Cell(0, 5.5, $this->safe($r[1]), 0, 1, 'L');
        }
        $pdf->Ln(4);

        /* ── Section 1 · PMs executed ─────────────────────────────────── */
        $pms = $db->mySelect(
            "SELECT ps.pm_no, ps.status, ps.started_at, ps.finished_at, ps.done_by_name, ps.client_decision,
                    a.asset_no, s.name AS site_name, t.code AS asset_code,
                    tpl.code AS template_code
               FROM pm_services ps
               JOIN service_contract_assets a  ON a.c0d = ps.contract_asset_id
          LEFT JOIN service_contract_sites s   ON s.c0d = a.site_id
          LEFT JOIN asset_types t              ON t.c0d = a.asset_type_id
          LEFT JOIN pm_templates tpl           ON tpl.c0d = ps.template_id
              WHERE ps.contract_id = :c
                AND ps.finished_at BETWEEN :ps AND :pe
              ORDER BY ps.finished_at",
            [':c' => $contractId, ':ps' => $periodStart . ' 00:00:00', ':pe' => $periodEnd . ' 23:59:59']
        ) ?: [];
        $this->sectionHeader($pdf, 'Preventive Maintenance executed (' . count($pms) . ')');
        if (!empty($pms)) {
            $pdf->setColumns([
                ['label' => 'PM #',       'width' => 18, 'align' => 'L'],
                ['label' => 'Site',       'width' => 26, 'align' => 'L'],
                ['label' => 'Asset',      'width' => 18, 'align' => 'L'],
                ['label' => 'Type',       'width' => 12, 'align' => 'L'],
                ['label' => 'Template',   'width' => 18, 'align' => 'L'],
                ['label' => 'Done',       'width' => 22, 'align' => 'L', 'type' => 'date'],
                ['label' => 'Done by',    'width' => 26, 'align' => 'L'],
                ['label' => 'Client',     'width' => 14, 'align' => 'L'],
                ['label' => 'Status',     'width' => 16, 'align' => 'L'],
            ]);
            $pdf->drawTableHeader();
            foreach ($pms as $r) {
                $pdf->drawRow([
                    $r['pm_no'], $r['site_name'] ?? '', $r['asset_no'] ?? '',
                    $r['asset_code'] ?? '', $r['template_code'] ?? '',
                    (string)($r['finished_at'] ?? ''), (string)($r['done_by_name'] ?? ''),
                    ucfirst(strtolower((string)($r['client_decision'] ?? '—'))),
                    ucwords(strtolower(str_replace('_', ' ', (string)$r['status']))),
                ]);
            }
        } else {
            $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
            $pdf->SetTextColor(100, 116, 139);
            $pdf->Cell(0, 6, 'No PMs executed in this period.', 0, 1, 'L');
        }
        $pdf->Ln(4);

        /* ── Section 2 · Callouts ─────────────────────────────────────── */
        $callouts = $db->mySelect(
            "SELECT co.callout_no, co.status, co.reported_at, co.resolved_at, co.is_emergency, co.labour_hrs, co.mileage_km,
                    co.sla_response_breached_hrs, co.sla_restore_breached_hrs,
                    cat.code AS cat_code, cat.name AS cat_name, cat.sla_response_hrs, cat.sla_restoration_hrs,
                    s.name AS site_name, a.asset_no
               FROM callouts co
          LEFT JOIN callout_categories cat ON cat.c0d = co.category_id
          LEFT JOIN service_contract_sites s ON s.c0d = co.site_id
          LEFT JOIN service_contract_assets a ON a.c0d = co.asset_id
              WHERE co.contract_id = :c
                AND co.status IN ('RESOLVED','CLIENT_ACCEPTED','CLOSED')
                AND co.resolved_at BETWEEN :ps AND :pe
              ORDER BY co.reported_at",
            [':c' => $contractId, ':ps' => $periodStart . ' 00:00:00', ':pe' => $periodEnd . ' 23:59:59']
        ) ?: [];
        $this->sectionHeader($pdf, 'Callouts resolved (' . count($callouts) . ')');
        if (!empty($callouts)) {
            $pdf->setColumns([
                ['label' => 'Callout #',  'width' => 22, 'align' => 'L'],
                ['label' => 'Site',       'width' => 26, 'align' => 'L'],
                ['label' => 'Asset',      'width' => 16, 'align' => 'L'],
                ['label' => 'Cat',        'width' => 12, 'align' => 'L'],
                ['label' => 'Reported',   'width' => 22, 'align' => 'L', 'type' => 'date'],
                ['label' => 'Resolved',   'width' => 22, 'align' => 'L', 'type' => 'date'],
                ['label' => 'Labour hrs', 'width' => 15, 'align' => 'R'],
                ['label' => 'Emerg?',     'width' => 10, 'align' => 'C'],
                ['label' => 'SLA',        'width' => 15, 'align' => 'L'],
            ]);
            $pdf->drawTableHeader();
            foreach ($callouts as $r) {
                $breach = ((float)$r['sla_response_breached_hrs'] > 0 || (float)$r['sla_restore_breached_hrs'] > 0);
                $slaLabel = $breach
                    ? ('BREACH R+' . number_format((float)$r['sla_response_breached_hrs'], 1) . 'h S+' . number_format((float)$r['sla_restore_breached_hrs'], 1) . 'h')
                    : 'MET';
                $pdf->drawRow([
                    $r['callout_no'], $r['site_name'] ?? '', $r['asset_no'] ?? '',
                    $r['cat_code'] ?? '', (string)$r['reported_at'], (string)$r['resolved_at'],
                    (string)($r['labour_hrs'] ?? '0'),
                    ((int)$r['is_emergency'] === 1 ? 'Y' : ''),
                    $slaLabel,
                ]);
            }
        } else {
            $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
            $pdf->SetTextColor(100, 116, 139);
            $pdf->Cell(0, 6, 'No callouts in this period.', 0, 1, 'L');
        }
        $pdf->Ln(4);

        /* ── Section 3 · SLA compliance summary ───────────────────────── */
        $slaSummary = [];
        foreach ($callouts as $r) {
            $cat = $r['cat_code'] ?? 'UNCAT';
            if (!isset($slaSummary[$cat])) $slaSummary[$cat] = ['total' => 0, 'met' => 0, 'breach' => 0, 'name' => $r['cat_name'] ?? $cat];
            $slaSummary[$cat]['total']++;
            if ((float)$r['sla_response_breached_hrs'] > 0 || (float)$r['sla_restore_breached_hrs'] > 0) $slaSummary[$cat]['breach']++;
            else                                                                                        $slaSummary[$cat]['met']++;
        }
        $this->sectionHeader($pdf, 'SLA Compliance');
        if (!empty($slaSummary)) {
            $pdf->setColumns([
                ['label' => 'Category',    'width' => 30, 'align' => 'L'],
                ['label' => 'Total',       'width' => 15, 'align' => 'R'],
                ['label' => 'Within SLA',  'width' => 22, 'align' => 'R'],
                ['label' => 'Breached',    'width' => 22, 'align' => 'R'],
                ['label' => 'Compliance %','width' => 25, 'align' => 'R'],
            ]);
            $pdf->drawTableHeader();
            $totAll = 0; $metAll = 0;
            foreach ($slaSummary as $cat => $s) {
                $pct = $s['total'] > 0 ? round(($s['met'] / $s['total']) * 100, 1) : 100;
                $pdf->drawRow([
                    $s['name'], (string)$s['total'], (string)$s['met'], (string)$s['breach'],
                    number_format($pct, 1) . ' %',
                ]);
                $totAll += $s['total']; $metAll += $s['met'];
            }
            $overall = $totAll > 0 ? round(($metAll / $totAll) * 100, 1) : 100;
            $pdf->drawFooter('Overall', ['', (string)$totAll, (string)$metAll, (string)($totAll - $metAll), number_format($overall, 1) . ' %']);
        } else {
            $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
            $pdf->SetTextColor(100, 116, 139);
            $pdf->Cell(0, 6, 'No SLA metrics — no callouts in period.', 0, 1, 'L');
        }
        $pdf->Ln(4);

        /* ── Section 4 · Parts consumed ───────────────────────────────── */
        $parts = $db->mySelect(
            "SELECT p.sku, p.name AS part_name, SUM(pu.qty) AS qty, MAX(pu.unit_cost_at_use) AS unit_cost, p.uom
               FROM callout_parts_used pu
               JOIN callouts co  ON co.c0d = pu.callout_id
          LEFT JOIN spare_parts p ON p.c0d = pu.part_id
              WHERE co.contract_id = :c
                AND co.resolved_at BETWEEN :ps AND :pe
              GROUP BY p.c0d, p.sku, p.name, p.uom
              UNION ALL
             SELECT p.sku, p.name AS part_name, SUM(pu.qty) AS qty, MAX(pu.unit_cost_at_use) AS unit_cost, p.uom
               FROM pm_service_parts_used pu
               JOIN pm_services ps ON ps.c0d = pu.pm_service_id
          LEFT JOIN spare_parts p   ON p.c0d = pu.part_id
              WHERE ps.contract_id = :c2
                AND ps.finished_at BETWEEN :ps2 AND :pe2
              GROUP BY p.c0d, p.sku, p.name, p.uom",
            [':c' => $contractId, ':ps' => $periodStart . ' 00:00:00', ':pe' => $periodEnd . ' 23:59:59',
             ':c2' => $contractId, ':ps2' => $periodStart . ' 00:00:00', ':pe2' => $periodEnd . ' 23:59:59']
        ) ?: [];
        $this->sectionHeader($pdf, 'Parts consumed (' . count($parts) . ')');
        if (!empty($parts)) {
            $pdf->setColumns([
                ['label' => 'SKU',       'width' => 22, 'align' => 'L'],
                ['label' => 'Part',      'width' => 60, 'align' => 'L'],
                ['label' => 'Qty',       'width' => 20, 'align' => 'R'],
                ['label' => 'UoM',       'width' => 15, 'align' => 'L'],
                ['label' => 'Unit cost', 'width' => 25, 'align' => 'R', 'type' => 'money'],
                ['label' => 'Line cost', 'width' => 28, 'align' => 'R', 'type' => 'money'],
            ]);
            $pdf->drawTableHeader();
            $totCost = 0.0;
            foreach ($parts as $r) {
                $line = (float)$r['qty'] * (float)($r['unit_cost'] ?? 0);
                $totCost += $line;
                $pdf->drawRow([
                    $r['sku'] ?? '', $r['part_name'] ?? '',
                    number_format((float)$r['qty'], (fmod((float)$r['qty'], 1) == 0 ? 0 : 2)),
                    $r['uom'] ?? '',
                    (string)($r['unit_cost'] ?? 0),
                    (string)$line,
                ]);
            }
            $pdf->drawFooter('Total (at cost)', ['', '', '', '', '', (string)$totCost]);
        } else {
            $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
            $pdf->SetTextColor(100, 116, 139);
            $pdf->Cell(0, 6, 'No parts consumed in period.', 0, 1, 'L');
        }
        $pdf->Ln(4);

        /* ── Section 5 · Cost summary (invoice preview) ───────────────── */
        $calc = null;
        try { $calc = $sc->calcConsumption($contractId, $year, $month); } catch (\Throwable $e) { /* keep null */ }
        $this->sectionHeader($pdf, 'Cost summary (invoice preview)');
        if ($calc && !empty($calc['lines'])) {
            $pdf->setColumns([
                ['label' => 'Line',      'width' => 90, 'align' => 'L'],
                ['label' => 'Qty',       'width' => 18, 'align' => 'R'],
                ['label' => 'Unit',      'width' => 12, 'align' => 'L'],
                ['label' => 'Unit price','width' => 25, 'align' => 'R', 'type' => 'money'],
                ['label' => 'Total',     'width' => 25, 'align' => 'R', 'type' => 'money'],
            ]);
            $pdf->drawTableHeader();
            foreach ($calc['lines'] as $l) {
                $pdf->drawRow([
                    $l['description'], (string)$l['qty'], $l['unit'],
                    (string)$l['unit_price'], (string)$l['line_total'],
                ]);
            }
            $pdf->drawFooter('Subtotal (' . $calc['currency'] . ')', ['', '', '', '', (string)$calc['subtotal']]);
        } else {
            $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
            $pdf->SetTextColor(100, 116, 139);
            $pdf->Cell(0, 6, 'Nothing billable in period.', 0, 1, 'L');
        }
        $pdf->Ln(6);

        /* ── Section 6 · Sign-off block ───────────────────────────────── */
        $this->sectionHeader($pdf, 'Sign-off');
        $pdf->SetFont('Roboto_Condensed-Regular', '', 9);
        $pdf->SetTextColor(51, 65, 85);
        $pdf->Cell(0, 5, 'Prepared by: __________________________     Date: ____________', 0, 1, 'L');
        $pdf->Ln(4);
        $pdf->Cell(0, 5, 'Reviewed by (PM): __________________________     Date: ____________', 0, 1, 'L');
        $pdf->Ln(4);
        $pdf->Cell(0, 5, 'Accepted by (Customer): __________________________     Date: ____________', 0, 1, 'L');

        return $pdf;
    }

    private function sectionHeader(RsPdfReport $pdf, string $title): void
    {
        if ($pdf->GetY() > $pdf->GetPageHeight() - 40) $pdf->AddPage();
        $pdf->SetFont('Roboto_Condensed-Bold', '', 11);
        $pdf->SetFillColor(241, 245, 249);
        $pdf->SetTextColor(51, 65, 85);
        $pdf->SetDrawColor(122, 139, 161);
        $pdf->SetLineWidth(0.4);
        $pdf->Cell(0, 7, ' ' . $this->safe($title), 'B', 1, 'L', true);
        $pdf->SetLineWidth(0.1);
        $pdf->Ln(2);
    }

    private function safe(string $s): string
    {
        $s = strtr($s, [
            "\u{2013}" => '-', "\u{2014}" => '-',
            "\u{2018}" => "'", "\u{2019}" => "'",
            "\u{201C}" => '"', "\u{201D}" => '"',
            "\u{2026}" => '...',
            "\u{2212}" => '-',
        ]);
        return @iconv('UTF-8', 'ISO-8859-1//TRANSLIT//IGNORE', $s) ?: $s;
    }
}
