<?php
/**
 * ServiceContractPacks · Slice 8Z-y.
 *
 * Per-contract spare-part packs + their line items. Free-text item labels so
 * PM can start immediately without a populated parts catalog. Later, an
 * `spare_part_id` FK column can be added to normalise against `spare_parts`.
 *
 * Each pack has its own supply_model (CLIENT / COMPANY / CONSIGNMENT / FIXED_PACK)
 * which overrides the contract-level spare_policy on a per-pack basis — that's the
 * Tanzania pattern where a Vodacom contract might be mostly client-supplied but
 * the callout kit is company-owned + consumption-billed.
 */
class ServiceContractPacks extends Model
{
    public const SUPPLY_MODELS = ['CLIENT','COMPANY','CONSIGNMENT','FIXED_PACK'];

    /** Lists packs with their items nested — one round-trip per contract. */
    public function listFor(int $contractId): array
    {
        $db = new DB();
        $packs = $db->mySelect(
            "SELECT * FROM service_contract_packs
              WHERE contract_id = :c AND deleted = 0
              ORDER BY sort_order, c0d",
            [':c' => $contractId]
        ) ?: [];
        if (empty($packs)) return [];

        $ids = array_map(fn($p) => (int)$p['c0d'], $packs);
        $inPh = implode(',', array_fill(0, count($ids), '?'));
        // PDO positional bind for the IN clause
        $items = $db->mySelect(
            "SELECT * FROM service_contract_pack_items
              WHERE pack_id IN ($inPh) AND deleted = 0
              ORDER BY pack_id, sort_order, c0d",
            $ids
        ) ?: [];
        $itemsByPack = [];
        foreach ($items as $it) $itemsByPack[(int)$it['pack_id']][] = $it;
        foreach ($packs as &$p) $p['items'] = $itemsByPack[(int)$p['c0d']] ?? [];
        unset($p);
        return $packs;
    }

    /** Upsert one pack (header). Items are separate — see itemSave/itemRemove. */
    public function save(int $contractId, array $d, int $userId): array
    {
        if ($contractId <= 0) return ['ok' => false, 'msg' => 'contract_id required.'];
        $name = trim((string)($d['name'] ?? ''));
        if ($name === '') return ['ok' => false, 'msg' => 'name required.'];
        $supply = strtoupper((string)($d['supply_model'] ?? 'CLIENT'));
        if (!in_array($supply, self::SUPPLY_MODELS, true)) $supply = 'CLIENT';

        $params = [
            ':c'    => $contractId,
            ':code' => trim((string)($d['code'] ?? '')) ?: null,
            ':n'    => $name,
            ':sm'   => $supply,
            ':lt'   => trim((string)($d['linked_template_slug'] ?? '')) ?: null,
            ':nt'   => trim((string)($d['notes'] ?? '')) ?: null,
            ':so'   => (int)($d['sort_order'] ?? 100),
        ];

        $db = new DB();
        $id = (int)($d['c0d'] ?? 0);
        if ($id > 0) {
            $u = [
                ':code' => $params[':code'], ':n' => $params[':n'], ':sm' => $params[':sm'],
                ':lt'   => $params[':lt'], ':nt' => $params[':nt'], ':so' => $params[':so'],
                ':eb'   => $userId, ':id' => $id,
            ];
            $db->insertUpdate(
                "UPDATE service_contract_packs
                    SET code = :code, name = :n, supply_model = :sm, linked_template_slug = :lt,
                        notes = :nt, sort_order = :so, edited_by = :eb, edited_on = NOW()
                  WHERE c0d = :id",
                $u
            );
            return ['ok' => true, 'id' => $id];
        }
        $params[':cb'] = $userId;
        $r = $db->insertUpdate(
            "INSERT INTO service_contract_packs
                (contract_id, code, name, supply_model, linked_template_slug, notes, sort_order,
                 created_by, created_on)
             VALUES (:c, :code, :n, :sm, :lt, :nt, :so, :cb, NOW())",
            $params
        );
        return ['ok' => true, 'id' => (int)($r['last_id'] ?? 0)];
    }

    public function remove(int $packId): array
    {
        if ($packId <= 0) return ['ok' => false, 'msg' => 'pack_id required.'];
        $db = new DB();
        // Soft-delete the pack + its items so the audit trail survives.
        $db->insertUpdate("UPDATE service_contract_packs SET deleted = 1, edited_on = NOW() WHERE c0d = :id", [':id' => $packId]);
        $db->insertUpdate("UPDATE service_contract_pack_items SET deleted = 1 WHERE pack_id = :p", [':p' => $packId]);
        return ['ok' => true];
    }

    /** Upsert one pack item (line). */
    public function itemSave(int $packId, array $d): array
    {
        if ($packId <= 0) return ['ok' => false, 'msg' => 'pack_id required.'];
        $itemName = trim((string)($d['item_name'] ?? ''));
        if ($itemName === '') return ['ok' => false, 'msg' => 'item_name required.'];
        $qty = isset($d['qty']) && $d['qty'] !== '' ? (float)$d['qty'] : 1.0;

        $params = [
            ':p'    => $packId,
            ':il'   => trim((string)($d['interval_label'] ?? '')) ?: null,
            ':nm'   => $itemName,
            ':q'    => $qty,
            ':u'    => trim((string)($d['uom'] ?? '')) ?: null,
            ':nt'   => trim((string)($d['notes'] ?? '')) ?: null,
            ':so'   => (int)($d['sort_order'] ?? 100),
        ];

        $db = new DB();
        $id = (int)($d['c0d'] ?? 0);
        if ($id > 0) {
            $u = [
                ':il' => $params[':il'], ':nm' => $params[':nm'], ':q' => $params[':q'],
                ':u'  => $params[':u'],  ':nt' => $params[':nt'], ':so' => $params[':so'],
                ':id' => $id,
            ];
            $db->insertUpdate(
                "UPDATE service_contract_pack_items
                    SET interval_label = :il, item_name = :nm, qty = :q, uom = :u,
                        notes = :nt, sort_order = :so
                  WHERE c0d = :id",
                $u
            );
            return ['ok' => true, 'id' => $id];
        }
        $r = $db->insertUpdate(
            "INSERT INTO service_contract_pack_items
                (pack_id, interval_label, item_name, qty, uom, notes, sort_order)
             VALUES (:p, :il, :nm, :q, :u, :nt, :so)",
            $params
        );
        return ['ok' => true, 'id' => (int)($r['last_id'] ?? 0)];
    }

    public function itemRemove(int $itemId): array
    {
        if ($itemId <= 0) return ['ok' => false, 'msg' => 'item_id required.'];
        $db = new DB();
        $db->insertUpdate("UPDATE service_contract_pack_items SET deleted = 1 WHERE c0d = :id", [':id' => $itemId]);
        return ['ok' => true];
    }
}
