<?php

namespace App\Services;

use App\Models\OrderModel;
use App\Models\PaymentMethodModel;
use App\Models\PaymentModel;

/** Records a payment and synchronizes the related order, invoice, and PO queue. */
class PaymentService
{
    private OrderModel $orderModel;
    private PaymentModel $paymentModel;
    private PaymentMethodModel $paymentMethodModel;
    private InvoiceService $invoiceService;
    private ProductionQueueService $productionQueueService;

    public function __construct(
        ?OrderModel $orderModel = null,
        ?PaymentModel $paymentModel = null,
        ?PaymentMethodModel $paymentMethodModel = null,
        ?InvoiceService $invoiceService = null,
        ?ProductionQueueService $productionQueueService = null
    ) {
        $this->orderModel = $orderModel ?? new OrderModel();
        $this->paymentModel = $paymentModel ?? new PaymentModel();
        $this->paymentMethodModel = $paymentMethodModel ?? new PaymentMethodModel();
        $this->invoiceService = $invoiceService ?? new InvoiceService();
        $this->productionQueueService = $productionQueueService ?? new ProductionQueueService();
    }

    public function record(int $orderId, float $amount, int $methodId, string $status = 'verified'): array
    {
        $order = $this->orderModel->find($orderId);
        $method = $this->paymentMethodModel->find($methodId);

        if (!$order || !$method || empty($method['is_active'])) {
            throw new \RuntimeException('Order atau metode pembayaran tidak valid.');
        }

        $totalPaid = $this->paymentModel->getTotalPaid($orderId);
        $remaining = max(0, (float) $order['total'] - $totalPaid);

        if ($amount <= 0 || $amount > $remaining) {
            throw new \RuntimeException('Jumlah pembayaran harus lebih dari nol dan tidak boleh melebihi sisa tagihan.');
        }

        $db = \Config\Database::connect();
        $paymentData = [
            'id_order' => $orderId,
            'id_payment_method' => $methodId,
            'tanggal_bayar' => date('Y-m-d H:i:s'),
            'jumlah_bayar' => $amount,
            'status' => $status,
        ];

        if ($db->fieldExists('created_at', 'payments')) {
            $paymentData['created_at'] = date('Y-m-d H:i:s');
        }

        if (!$db->table('payments')->insert($paymentData)) {
            throw new \RuntimeException('Gagal menyimpan pembayaran.');
        }

        if (!$this->orderModel->update($orderId, [
            'payment_method' => $method['kode'] ?? 'cash',
        ])) {
            throw new \RuntimeException('Gagal memperbarui metode pembayaran order.');
        }

        $order = $this->syncOrderPaymentState($orderId);
        $invoice = $this->invoiceService->syncForOrder($order);

        if (($order['order_type'] ?? null) === 'po' && ($order['order_status'] ?? null) === 'production') {
            $this->productionQueueService->createForOrder($orderId, $order['target_date'] ?? null);
        }

        return ['order' => $order, 'invoice' => $invoice];
    }

    public function syncOrderPaymentState(int $orderId): array
    {
        $order = $this->orderModel->find($orderId);
        if (!$order) {
            throw new \RuntimeException('Order tidak ditemukan.');
        }

        $paidAmount = $this->paymentModel->getTotalPaid($orderId);
        $remainingAmount = $this->orderModel->calculateRemaining((float) $order['total'], $paidAmount);
        $paymentStatus = $this->orderModel->calculatePaymentStatus((float) $order['total'], $paidAmount);
        $orderStatus = $order['order_status'] ?? 'waiting_payment';

        if ($orderStatus === 'draft' || $orderStatus === 'waiting_payment') {
            if ($paidAmount <= 0) {
                $orderStatus = 'waiting_payment';
            } elseif (($order['order_type'] ?? null) === 'po') {
                $orderStatus = 'production';
            } else {
                $orderStatus = 'completed';
            }
        }

        if (!$this->orderModel->update($orderId, [
            'paid_amount' => $paidAmount,
            'remaining_amount' => $remainingAmount,
            'payment_status' => $paymentStatus,
            'order_status' => $orderStatus,
        ])) {
            throw new \RuntimeException('Gagal memperbarui status pembayaran order.');
        }

        return $this->orderModel->find($orderId) ?? throw new \RuntimeException('Order tidak ditemukan setelah pembayaran disimpan.');
    }
}
