<?php

declare(strict_types=1);

namespace App\Repositories;

use PDO;

final class OpeningStockRepository
{
    public function __construct(private PDO $pdo) {}

    public function nextDocNo(): string
    {
        $prefix = 'OP-' . date('Y') . '-';
        $st = $this->pdo->prepare("SELECT doc_no FROM opening_docs WHERE doc_no LIKE ? ORDER BY id DESC LIMIT 1");
        $st->execute([$prefix.'%']);
        $last = (string)($st->fetchColumn() ?: '');
        if ($last && preg_match('/^(.*-)(\d+)$/', $last, $m)) {
            $n = (int)$m[2] + 1;
        } else {
            $n = 1;
        }
        return $prefix . str_pad((string)$n, 5, '0', STR_PAD_LEFT);
    }

    public function activeWarehouses(): array { return $this->pdo->query("SELECT id, name FROM warehouses WHERE is_active=1 ORDER BY name")->fetchAll(); }
    public function activeItems(): array { return $this->pdo->query("SELECT id, name FROM items WHERE is_active=1 ORDER BY name")->fetchAll(); }
    public function allUnits(): array { return $this->pdo->query("SELECT id, name FROM units ORDER BY name")->fetchAll(); }

    public function createDoc(array $data): int
    {
        $st = $this->pdo->prepare("INSERT INTO opening_docs (doc_no, doc_date, warehouse_id, status, notes, created_by) VALUES (?,?,?,?,?,?)");
        $st->execute([$data['doc_no'], $data['doc_date'], $data['warehouse_id'], 'DRAFT', $data['notes'], $data['created_by']]);
        return (int)$this->pdo->lastInsertId();
    }

    public function findDoc(int $id): array|false
    {
        $st = $this->pdo->prepare("SELECT d.*, w.name warehouse_name FROM opening_docs d JOIN warehouses w ON w.id=d.warehouse_id WHERE d.id=?");
        $st->execute([$id]);
        return $st->fetch();
    }

    public function docWarehouseId(int $docId): int
    {
        return (int)$this->pdo->query("SELECT warehouse_id FROM opening_docs WHERE id=" . $docId)->fetchColumn();
    }

    public function itemAlreadyOpened(int $warehouseId, int $itemId): bool
    {
        $st = $this->pdo->prepare("SELECT COUNT(*) FROM stock_moves WHERE ref_type='OPENING_DOC' AND warehouse_id=? AND item_id=?");
        $st->execute([$warehouseId, $itemId]);
        return (int)$st->fetchColumn() > 0;
    }

    public function addLine(int $docId, int $itemId, ?int $unitId, float $qty, float $cost): void
    {
        $this->pdo->prepare("INSERT INTO opening_doc_lines (doc_id, item_id, unit_id, qty, cost) VALUES (?,?,?,?,?)")
            ->execute([$docId, $itemId, $unitId, $qty, $cost]);
    }

    public function updateLine(int $docId, int $lineId, ?int $unitId, float $qty, float $cost): void
    {
        $this->pdo->prepare("UPDATE opening_doc_lines SET unit_id=?, qty=?, cost=? WHERE id=? AND doc_id=?")
            ->execute([$unitId, $qty, $cost, $lineId, $docId]);
    }

    public function deleteLine(int $docId, int $lineId): void
    {
        $this->pdo->prepare("DELETE FROM opening_doc_lines WHERE id=? AND doc_id=?")->execute([$lineId, $docId]);
    }

    public function deleteDraftDoc(int $docId): void
    {
        $this->pdo->prepare("DELETE FROM opening_doc_lines WHERE doc_id=?")->execute([$docId]);
        $this->pdo->prepare("DELETE FROM opening_docs WHERE id=? AND status='DRAFT'")->execute([$docId]);
    }

    public function linesForDoc(int $docId): array
    {
        $st = $this->pdo->prepare("SELECT l.*, i.name item_name, u.name unit_name
                            FROM opening_doc_lines l
                            JOIN items i ON i.id=l.item_id
                            LEFT JOIN units u ON u.id=l.unit_id
                            WHERE l.doc_id=? ORDER BY l.id");
        $st->execute([$docId]);
        return $st->fetchAll();
    }

    public function listDocs(): array
    {
        return $this->pdo->query("SELECT d.*, w.name warehouse_name
                     FROM opening_docs d
                     JOIN warehouses w ON w.id=d.warehouse_id
                     ORDER BY d.id DESC LIMIT 200")->fetchAll();
    }

    public function markPosted(int $docId): void
    {
        $this->pdo->prepare("UPDATE opening_docs SET status='POSTED', posted_at=NOW() WHERE id=?")->execute([$docId]);
    }

    public function insertStockMove(int $docId, int $warehouseId, int $itemId, float $qtyBase, float $cost, int $userId): void
    {
        $this->pdo->prepare("INSERT INTO stock_moves (ref_type, ref_id, warehouse_id, item_id, qty_in, qty_out, cost, user_id, created_at)
                           VALUES ('OPENING_DOC',?,?,?,?,?,?,?,NOW())")
            ->execute([$docId, $warehouseId, $itemId, $qtyBase, 0, $cost, $userId]);
    }
}
