<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Persistence\Repositories;

use ApiModel\Domain\Repository\PurchasePaymentRepositoryInterface;
use ApiModel\Infrastructure\Persistence\Database;
use PDO;

final class PdoPurchasePaymentRepository implements PurchasePaymentRepositoryInterface
{
    public function __construct(private readonly PDO $pdo) {}

    public function listByCompany(string $companyId, ?string $branchId = null): array
    {
        $sql = 'SELECT p.*, c.name as vendor_name, a.code as account_code, a.name as account_name,
                       wa.code as withholding_account_code, wa.name as withholding_account_name
                FROM purchases_payments p
                JOIN contacts c ON p.vendor_id = c.id
                JOIN chart_accounts a ON p.chart_account_id = a.id
                LEFT JOIN chart_accounts wa ON p.withholding_account_id = wa.id
                WHERE p.company_id = ?';
        $params = [$companyId];

        if ($branchId !== null && $branchId !== '') {
            $sql .= ' AND p.branch_id = ?';
            $params[] = $branchId;
        }

        $sql .= ' ORDER BY p.payment_date DESC, p.created_at DESC';

        $st = $this->pdo->prepare($sql);
        $st->execute($params);

        return $st->fetchAll(PDO::FETCH_ASSOC);
    }

    public function findById(string $id): ?array
    {
        $st = $this->pdo->prepare(
            'SELECT p.*, c.name as vendor_name, a.code as account_code, a.name as account_name,
                    wa.code as withholding_account_code, wa.name as withholding_account_name
             FROM purchases_payments p
             JOIN contacts c ON p.vendor_id = c.id
             JOIN chart_accounts a ON p.chart_account_id = a.id
             LEFT JOIN chart_accounts wa ON p.withholding_account_id = wa.id
             WHERE p.id = ?
             LIMIT 1'
        );
        $st->execute([$id]);
        $row = $st->fetch(PDO::FETCH_ASSOC);

        return $row !== false ? $row : null;
    }

    public function findLinesByPaymentId(string $paymentId): array
    {
        $st = $this->pdo->prepare(
            'SELECT l.*, b.bill_number, b.total as bill_total, b.balance as bill_balance
             FROM purchases_payment_lines l
             JOIN purchases_bills b ON l.bill_id = b.id
             WHERE l.payment_id = ?'
        );
        $st->execute([$paymentId]);

        return $st->fetchAll(PDO::FETCH_ASSOC);
    }

    public function insert(array $payment): void
    {
        $st = $this->pdo->prepare(
            'INSERT INTO purchases_payments (
                id, company_id, branch_id, vendor_id, payment_number, payment_date,
                payment_method, amount, currency_code, exchange_rate, chart_account_id, notes, created_by,
                withholding_amount, withholding_account_id
             ) VALUES (
                :id, :company_id, :branch_id, :vendor_id, :payment_number, :payment_date,
                :payment_method, :amount, :currency_code, :exchange_rate, :chart_account_id, :notes, :created_by,
                :withholding_amount, :withholding_account_id
             )'
        );
        $st->execute([
            'id' => $payment['id'],
            'company_id' => $payment['company_id'],
            'branch_id' => $payment['branch_id'] ?: null,
            'vendor_id' => $payment['vendor_id'],
            'payment_number' => $payment['payment_number'],
            'payment_date' => $payment['payment_date'],
            'payment_method' => $payment['payment_method'] ?: 'cash',
            'amount' => $payment['amount'],
            'currency_code' => $payment['currency_code'] ?: 'USD',
            'exchange_rate' => $payment['exchange_rate'],
            'chart_account_id' => $payment['chart_account_id'],
            'notes' => $payment['notes'] ?: null,
            'created_by' => $payment['created_by'] ?: null,
            'withholding_amount' => $payment['withholding_amount'] ?? 0.0,
            'withholding_account_id' => $payment['withholding_account_id'] ?: null,
        ]);
    }

    public function insertLines(string $paymentId, array $lines): void
    {
        $st = $this->pdo->prepare(
            'INSERT INTO purchases_payment_lines (id, payment_id, bill_id, amount)
             VALUES (?, ?, ?, ?)'
        );

        foreach ($lines as $line) {
            $id = $line['id'] ?? Database::uuid();
            $st->execute([
                $id,
                $paymentId,
                $line['bill_id'],
                $line['amount'],
            ]);
        }
    }

    public function delete(string $id): void
    {
        $st = $this->pdo->prepare('DELETE FROM purchases_payments WHERE id = ?');
        $st->execute([$id]);
    }

    public function nextPaymentNumber(string $companyId): string
    {
        $st = $this->pdo->prepare('SELECT COUNT(*) FROM purchases_payments WHERE company_id = ?');
        $st->execute([$companyId]);
        $count = (int) $st->fetchColumn();

        return 'RP-' . str_pad((string) ($count + 1), 6, '0', STR_PAD_LEFT);
    }
}
