<?php
/**
 * SpareParts — Slice 8S-1 · Services Master Data
 *
 * SKU catalogue with cost, unit, category, default markup. Referenced by service_pack_items
 * (planned spares for PMs) and by adhoc callout parts usage (Slice S4).
 */
class SpareParts extends Model
{
    public function list(bool $activeOnly = false, ?int $assetTypeId = null, string $search = ''): array
    {
        $db = new DB();
        $params = [];
        $where = "WHERE 1=1";
        if ($activeOnly)                { $where .= " AND s.is_active = 1"; }
        if ($assetTypeId !== null && $assetTypeId > 0) { $where .= " AND s.asset_type_id = :a"; $params[':a'] = $assetTypeId; }
        if ($search !== '')             { $where .= " AND (s.sku LIKE :q OR s.name LIKE :q)"; $params[':q'] = '%' . $search . '%'; }
        return $db->mySelect(
            "SELECT s.c0d, s.sku, s.name, s.description, s.uom, s.category,
                    s.unit_cost, s.currency, s.default_markup_pct, s.is_active,
                    a.code AS asset_type_code, a.name AS asset_type_name
               FROM spare_parts s
          LEFT JOIN asset_types a ON a.c0d = s.asset_type_id
               $where
              ORDER BY s.sku",
            $params
        ) ?: [];
    }

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

    public function save(array $d, int $uid): int
    {
        $sku  = strtoupper(trim((string)($d['sku'] ?? '')));
        $name = trim((string)($d['name'] ?? ''));
        if ($sku === '' || $name === '') throw new InvalidArgumentException('SKU + name required.');
        if (!preg_match('/^[A-Z0-9_.\-]{2,64}$/', $sku)) throw new InvalidArgumentException('SKU: 2-64 chars, A-Z/0-9/./_/- only.');

        $db = new DB();
        $id = (int)($d['c0d'] ?? 0);
        $data = [
            ':sku'  => $sku,
            ':n'    => $name,
            ':d'    => trim((string)($d['description'] ?? '')) ?: null,
            ':u'    => trim((string)($d['uom'] ?? 'ea')) ?: 'ea',
            ':cat'  => trim((string)($d['category'] ?? '')) ?: null,
            ':at'   => !empty($d['asset_type_id']) ? (int)$d['asset_type_id'] : null,
            ':uc'   => isset($d['unit_cost']) && $d['unit_cost'] !== '' ? (float)$d['unit_cost'] : null,
            ':cur'  => strtoupper(trim((string)($d['currency'] ?? 'TZS'))) ?: 'TZS',
            ':mk'   => isset($d['default_markup_pct']) && $d['default_markup_pct'] !== '' ? (float)$d['default_markup_pct'] : 25,
            ':a'    => !empty($d['is_active']) ? 1 : 0,
        ];
        if ($id > 0) {
            $data[':id'] = $id;
            $db->insertUpdate(
                "UPDATE spare_parts SET sku=:sku, name=:n, description=:d, uom=:u, category=:cat, asset_type_id=:at,
                    unit_cost=:uc, currency=:cur, default_markup_pct=:mk, is_active=:a, edited_on=NOW()
                  WHERE c0d=:id",
                $data
            );
            return $id;
        }
        $data[':ub'] = $uid;
        $fb = $db->insertUpdate(
            "INSERT INTO spare_parts (sku, name, description, uom, category, asset_type_id,
                unit_cost, currency, default_markup_pct, is_active, created_by)
             VALUES (:sku, :n, :d, :u, :cat, :at, :uc, :cur, :mk, :a, :ub)",
            $data
        );
        return (int)($fb['last_id'] ?? 0);
    }

    public function delete(int $id): void
    {
        $db = new DB();
        $refs = $db->mySelect("SELECT COUNT(*) n FROM service_pack_items WHERE part_id = :id", [':id' => $id]);
        if (!empty($refs) && (int)$refs[0]['n'] > 0) throw new RuntimeException('Cannot delete — part is used in service packs. Deactivate instead.');
        $db->insertUpdate("DELETE FROM spare_parts WHERE c0d = :id", [':id' => $id]);
    }

    /** Sell price = unit_cost × (1 + markup_pct / 100). */
    public function sellPrice(int $id): float
    {
        $p = $this->find($id);
        if (empty($p) || $p['unit_cost'] === null) return 0.0;
        return round((float)$p['unit_cost'] * (1 + (float)$p['default_markup_pct'] / 100), 2);
    }
}
