<?php
/**
 * TenderItems · buyer-facing item list per tender (Slice 8L).
 *
 * Neutral list — no cost, no markup. Answers "what does the buyer want?"
 * The Pricing tab later either seeds its own lines from these, or is
 * built lumpsum-only.
 *
 * line_kind guidance (defaultKindFor):
 *   goods       → GOOD
 *   services    → SERVICE
 *   works       → WORKS_BOQ
 *   consultancy → SERVICE
 * LOGISTICS/OTHER are always available regardless of project_type.
 */
class TenderItems extends Model
{
    public const KINDS = ['GOOD','SERVICE','WORKS_BOQ','LOGISTICS','OTHER'];

    public static function defaultKindFor(string $projectType): string
    {
        return match ($projectType) {
            'goods'       => 'GOOD',
            'services'    => 'SERVICE',
            'works'       => 'WORKS_BOQ',
            'consultancy' => 'SERVICE',
            default       => 'OTHER',
        };
    }

    public function listFor(int $tenderId): array
    {
        $db = new DB();
        return $db->mySelect(
            "SELECT * FROM tender_items
              WHERE tender_id = :t AND deleted = 0
              ORDER BY line_no, c0d",
            [':t' => $tenderId]
        ) ?: [];
    }

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

    public function nextLineNo(int $tenderId): int
    {
        $db = new DB();
        $r = $db->mySelect(
            "SELECT COALESCE(MAX(line_no), 0) + 1 AS n
               FROM tender_items WHERE tender_id = :t AND deleted = 0",
            [':t' => $tenderId]
        );
        return (int)($r[0]['n'] ?? 1);
    }

    public function add(int $tenderId, array $row, int $userId, string $userName): array
    {
        $desc = trim((string)($row['description'] ?? ''));
        if ($desc === '') return ['ok' => false, 'msg' => 'Description is required.'];

        $incoming = strtoupper(trim((string)($row['line_kind'] ?? '')));
        if ($incoming !== '' && in_array($incoming, self::KINDS, true)) {
            $kind = $incoming;
        } else {
            // Fall back to the tender's project_type default so caller can omit line_kind.
            $tRow = (new DB())->mySelect("SELECT project_type FROM tender_tracker WHERE c0d = :t", [':t' => $tenderId]);
            $kind = self::defaultKindFor((string)($tRow[0]['project_type'] ?? ''));
        }

        $qty = (float)($row['qty'] ?? 1);
        if ($qty <= 0) $qty = 1;

        $db = new DB();
        $r = $db->insertUpdate(
            "INSERT INTO tender_items
                (tender_id, line_no, item_ref, description, qty, uom, spec_notes, line_kind,
                 created_by, created_by_name, created_on)
             VALUES
                (:t, :ln, :ir, :d, :q, :u, :sn, :k,
                 :cb, :cbn, NOW())",
            [
                ':t'   => $tenderId,
                ':ln'  => $this->nextLineNo($tenderId),
                ':ir'  => (string)($row['item_ref'] ?? '') !== '' ? (string)$row['item_ref'] : null,
                ':d'   => $desc,
                ':q'   => $qty,
                ':u'   => (string)($row['uom'] ?? '') !== '' ? (string)$row['uom'] : null,
                ':sn'  => (string)($row['spec_notes'] ?? '') !== '' ? (string)$row['spec_notes'] : null,
                ':k'   => $kind,
                ':cb'  => $userId,
                ':cbn' => $userName,
            ]
        );
        return ['ok' => true, 'id' => (int)($r['last_id'] ?? 0)];
    }

    public function update(int $itemId, array $row, int $userId): array
    {
        $it = $this->find($itemId);
        if (!$it) return ['ok' => false, 'msg' => 'Item not found.'];

        $desc = trim((string)($row['description'] ?? $it['description']));
        if ($desc === '') return ['ok' => false, 'msg' => 'Description is required.'];

        $kind = strtoupper((string)($row['line_kind'] ?? $it['line_kind']));
        if (!in_array($kind, self::KINDS, true)) $kind = $it['line_kind'];

        $qty = (float)($row['qty'] ?? $it['qty']);
        if ($qty <= 0) $qty = 1;

        $db = new DB();
        $db->insertUpdate(
            "UPDATE tender_items
                SET item_ref = :ir, description = :d, qty = :q, uom = :u,
                    spec_notes = :sn, line_kind = :k,
                    edited_by = :eb, edited_on = NOW()
              WHERE c0d = :id",
            [
                ':ir' => (string)($row['item_ref'] ?? '') !== '' ? (string)$row['item_ref'] : null,
                ':d'  => $desc,
                ':q'  => $qty,
                ':u'  => (string)($row['uom'] ?? '') !== '' ? (string)$row['uom'] : null,
                ':sn' => (string)($row['spec_notes'] ?? '') !== '' ? (string)$row['spec_notes'] : null,
                ':k'  => $kind,
                ':eb' => $userId,
                ':id' => $itemId,
            ]
        );
        return ['ok' => true];
    }

    public function remove(int $itemId, int $userId): array
    {
        $it = $this->find($itemId);
        if (!$it) return ['ok' => false, 'msg' => 'Item not found.'];
        $db = new DB();
        $db->insertUpdate(
            "UPDATE tender_items SET deleted = 1, edited_by = :eb, edited_on = NOW() WHERE c0d = :id",
            [':eb' => $userId, ':id' => $itemId]
        );
        return ['ok' => true];
    }

    /** Reorder: $order is an array of item ids in the new order. Missing ids keep their old line_no. */
    public function reorder(int $tenderId, array $order): array
    {
        $db = new DB();
        $n = 0;
        foreach ($order as $lineNo => $id) {
            $id = (int)$id;
            if ($id <= 0) continue;
            $db->insertUpdate(
                "UPDATE tender_items SET line_no = :ln WHERE c0d = :id AND tender_id = :t AND deleted = 0",
                [':ln' => (int)$lineNo + 1, ':id' => $id, ':t' => $tenderId]
            );
            $n++;
        }
        return ['ok' => true, 'count' => $n];
    }

    /** Bulk import: $rows = [ [description, qty, uom, item_ref, spec_notes, line_kind], … ] */
    public function bulkImport(int $tenderId, array $rows, int $userId, string $userName): array
    {
        $added = 0; $errs = [];
        foreach ($rows as $idx => $r) {
            $res = $this->add($tenderId, $r, $userId, $userName);
            if ($res['ok']) $added++;
            else $errs[] = 'row ' . ($idx + 1) . ': ' . ($res['msg'] ?? '?');
        }
        return ['ok' => empty($errs), 'added' => $added, 'errors' => $errs];
    }
}
