<?php
/**
 * ServiceContractAssetSpecs · Slice 8Z-z-B.
 *
 * Per-contract equipment blueprints. PC creates one per standard configuration
 * ("Cummins C40 40kVA diesel · 12-mo warranty") and then applies it in bulk to
 * selected sites. Each generated service_contract_assets row FKs back via
 * service_contract_assets.spec_id so we can later report "all sites running spec X".
 */
class ServiceContractAssetSpecs extends Model
{
    /** Blueprints for one contract, joined with asset_types for icon + label. */
    public function listFor(int $contractId): array
    {
        return (new DB())->mySelect(
            "SELECT s.*, t.code AS asset_type_code, t.name AS asset_type_name, t.icon AS asset_type_icon,
                    (SELECT COUNT(*) FROM service_contract_assets a WHERE a.spec_id = s.c0d AND a.is_active = 1) AS units_deployed
               FROM service_contract_asset_specs s
          LEFT JOIN asset_types t ON t.c0d = s.asset_type_id
              WHERE s.contract_id = :c AND s.deleted = 0
              ORDER BY t.name, s.spec_code",
            [':c' => $contractId]
        ) ?: [];
    }

    /** Upsert one blueprint. spec_code must be unique per contract. */
    public function save(int $contractId, array $d, int $userId): array
    {
        if ($contractId <= 0) return ['ok' => false, 'msg' => 'contract_id required.'];
        $code = strtoupper(trim((string)($d['spec_code'] ?? '')));
        if ($code === '') return ['ok' => false, 'msg' => 'spec_code required.'];
        $name = trim((string)($d['spec_name'] ?? ''));
        if ($name === '') return ['ok' => false, 'msg' => 'spec_name required.'];
        $typeId = (int)($d['asset_type_id'] ?? 0);
        if ($typeId <= 0) return ['ok' => false, 'msg' => 'asset_type_id required.'];

        $params = [
            ':c'  => $contractId,
            ':sc' => $code,
            ':sn' => $name,
            ':t'  => $typeId,
            ':mk' => trim((string)($d['make'] ?? '')) ?: null,
            ':md' => trim((string)($d['model'] ?? '')) ?: null,
            ':sv' => isset($d['size_value']) && $d['size_value'] !== '' ? (int)$d['size_value'] : null,
            ':su' => trim((string)($d['size_unit'] ?? '')) ?: null,
            ':wm' => isset($d['default_warranty_months']) && $d['default_warranty_months'] !== '' ? (int)$d['default_warranty_months'] : null,
            ':hs' => isset($d['default_hours_run_seed'])  && $d['default_hours_run_seed']  !== '' ? (int)$d['default_hours_run_seed']  : null,
            ':mj' => trim((string)($d['meta_defaults_json'] ?? '')) ?: null,
            ':lt' => isset($d['linked_pm_template_id']) && $d['linked_pm_template_id'] !== '' ? (int)$d['linked_pm_template_id'] : null,
            ':nt' => trim((string)($d['notes'] ?? '')) ?: null,
            ':a'  => !empty($d['is_active']) ? 1 : 1,   // active by default
        ];

        $db = new DB();
        $id = (int)($d['c0d'] ?? 0);
        if ($id > 0) {
            $u = $params;
            unset($u[':c']);
            $u[':id'] = $id;
            $u[':eb'] = $userId;
            $db->insertUpdate(
                "UPDATE service_contract_asset_specs
                    SET spec_code=:sc, spec_name=:sn, asset_type_id=:t, make=:mk, model=:md,
                        size_value=:sv, size_unit=:su, default_warranty_months=:wm,
                        default_hours_run_seed=:hs, meta_defaults_json=:mj,
                        linked_pm_template_id=:lt, notes=:nt, is_active=:a,
                        edited_by=:eb, edited_on=NOW()
                  WHERE c0d=:id",
                $u
            );
            return ['ok' => true, 'id' => $id];
        }
        $params[':cb'] = $userId;
        try {
            $r = $db->insertUpdate(
                "INSERT INTO service_contract_asset_specs
                    (contract_id, spec_code, spec_name, asset_type_id, make, model, size_value, size_unit,
                     default_warranty_months, default_hours_run_seed, meta_defaults_json,
                     linked_pm_template_id, notes, is_active, created_by, created_on)
                 VALUES (:c, :sc, :sn, :t, :mk, :md, :sv, :su, :wm, :hs, :mj, :lt, :nt, :a, :cb, NOW())",
                $params
            );
        } catch (Throwable $e) {
            if (strpos($e->getMessage(), 'uq_contract_code') !== false) {
                return ['ok' => false, 'msg' => 'A blueprint with code "' . $code . '" already exists on this contract.'];
            }
            throw $e;
        }
        return ['ok' => true, 'id' => (int)($r['last_id'] ?? 0)];
    }

    public function remove(int $specId): array
    {
        if ($specId <= 0) return ['ok' => false, 'msg' => 'spec_id required.'];
        (new DB())->insertUpdate(
            "UPDATE service_contract_asset_specs SET deleted = 1, edited_on = NOW() WHERE c0d = :id",
            [':id' => $specId]
        );
        return ['ok' => true];
    }

    public function find(int $specId): ?array
    {
        $r = (new DB())->mySelect(
            "SELECT * FROM service_contract_asset_specs WHERE c0d = :id AND deleted = 0",
            [':id' => $specId]
        );
        return $r[0] ?? null;
    }

    /**
     * Bulk-apply one blueprint to selected sites: creates N × M asset rows.
     * Returns per-site counts so the UI can toast a summary + refresh.
     *
     * $siteIds — array of int site IDs (must belong to same contract as $specId).
     * $qtyPerSite — how many units to install per site (default 1).
     */
    public function applyToSites(int $specId, array $siteIds, int $qtyPerSite, int $userId): array
    {
        if ($specId <= 0) return ['ok' => false, 'msg' => 'spec_id required.'];
        if (empty($siteIds)) return ['ok' => false, 'msg' => 'Pick at least one site.'];
        if ($qtyPerSite < 1) $qtyPerSite = 1;
        if ($qtyPerSite > 20) return ['ok' => false, 'msg' => 'Qty per site capped at 20.'];

        $spec = $this->find($specId);
        if (!$spec) return ['ok' => false, 'msg' => 'Blueprint not found.'];
        $cid = (int)$spec['contract_id'];

        $db = new DB();
        // Guard: only sites on the same contract.
        $inPh = implode(',', array_fill(0, count($siteIds), '?'));
        $valid = $db->mySelect(
            "SELECT c0d, site_code FROM service_contract_sites WHERE contract_id = ? AND c0d IN ($inPh) AND is_active = 1",
            array_merge([$cid], array_map('intval', $siteIds))
        ) ?: [];
        if (empty($valid)) return ['ok' => false, 'msg' => 'None of the picked sites belong to this contract.'];

        $created = 0;
        foreach ($valid as $siteRow) {
            $sid = (int)$siteRow['c0d'];
            $siteCode = (string)($siteRow['site_code'] ?? '');
            for ($i = 1; $i <= $qtyPerSite; $i++) {
                // Auto-generate a per-unit asset_no. Example: VDC-GEN-40-CST-001-01
                $assetNo = trim($spec['spec_code']) . '-' . ($siteCode ?: 'S' . $sid) . '-' . str_pad((string)$i, 2, '0', STR_PAD_LEFT);
                // Compute warranty_end from default_warranty_months (if set) and today
                $warrantyEnd = null;
                if (!empty($spec['default_warranty_months'])) {
                    $warrantyEnd = date('Y-m-d', strtotime('+' . (int)$spec['default_warranty_months'] . ' months'));
                }
                $db->insertUpdate(
                    "INSERT INTO service_contract_assets
                        (contract_id, site_id, asset_type_id, asset_no, serial_no,
                         make, model, size_value, size_unit, install_date, warranty_end,
                         hours_run, meta_json, is_active, spec_id)
                     VALUES (:c, :s, :t, :an, NULL,
                             :mk, :md, :sv, :su, CURDATE(), :we,
                             :hr, :mj, 1, :sp)",
                    [
                        ':c'  => $cid, ':s' => $sid, ':t' => (int)$spec['asset_type_id'],
                        ':an' => $assetNo,
                        ':mk' => $spec['make'], ':md' => $spec['model'],
                        ':sv' => $spec['size_value'] !== null ? (int)$spec['size_value'] : null,
                        ':su' => $spec['size_unit'],
                        ':we' => $warrantyEnd,
                        ':hr' => $spec['default_hours_run_seed'] !== null ? (int)$spec['default_hours_run_seed'] : null,
                        ':mj' => $spec['meta_defaults_json'],
                        ':sp' => $specId,
                    ]
                );
                $created++;
            }
        }
        return ['ok' => true, 'created' => $created, 'sites_touched' => count($valid), 'qty_per_site' => $qtyPerSite];
    }
}
