<?php

namespace Modules\Procurement\Services;

use App\Models\PurchaseOrderModel;
use App\Models\PurchaseRequestModel;
use App\Models\RfqModel;
use App\Models\SupplierQuotationModel;

class ApprovalQueueService
{
    protected PurchaseRequestModel $purchaseRequests;
    protected RfqModel $rfqs;
    protected SupplierQuotationModel $supplierQuotations;
    protected PurchaseOrderModel $purchaseOrders;

    protected PurchaseRequestService $purchaseRequestService;
    protected RfqService $rfqService;
    protected SupplierQuotationService $supplierQuotationService;
    protected PurchaseOrderService $purchaseOrderService;

    public function __construct()
    {
        $this->purchaseRequests    = new PurchaseRequestModel();
        $this->rfqs                = new RfqModel();
        $this->supplierQuotations  = new SupplierQuotationModel();
        $this->purchaseOrders      = new PurchaseOrderModel();

        $this->purchaseRequestService   = new PurchaseRequestService();
        $this->rfqService               = new RfqService();
        $this->supplierQuotationService = new SupplierQuotationService();
        $this->purchaseOrderService     = new PurchaseOrderService();
    }

    /**
     * @return list<array{
     *   type: string,
     *   type_label: string,
     *   id: int,
     *   number: string,
     *   supplier_or_dept: string,
     *   date: string,
     *   total: float,
     *   approve_path: string,
     *   reject_path: string
     * }>
     */
    public function listPending(?string $search = null): array
    {
        $rows = [];

        foreach ($this->purchaseRequests->scopeForList($search, 'pending_approval')->findAll() as $row) {
            $rows[] = $this->mapRow(
                'purchase_request',
                'Purchase Request',
                (int) $row['id'],
                (string) $row['number'],
                (string) ($row['department'] ?: '—'),
                (string) ($row['request_date'] ?? ''),
                (float) ($row['total'] ?? 0)
            );
        }

        foreach ($this->rfqs->scopeForList($search, 'pending_approval')->findAll() as $row) {
            $rows[] = $this->mapRow(
                'rfq',
                'RFQ',
                (int) $row['id'],
                (string) $row['number'],
                (string) ($row['purchase_request_number'] ?: '—'),
                (string) ($row['rfq_date'] ?? ''),
                (float) ($row['total'] ?? 0)
            );
        }

        foreach ($this->supplierQuotations->scopeForList($search, 'pending_approval')->findAll() as $row) {
            $rows[] = $this->mapRow(
                'supplier_quotation',
                'Supplier Quotation',
                (int) $row['id'],
                (string) $row['number'],
                (string) ($row['supplier_name'] ?: '—'),
                (string) ($row['quotation_date'] ?? ''),
                (float) ($row['total'] ?? 0)
            );
        }

        foreach ($this->purchaseOrders->scopeForList($search, 'pending_approval')->findAll() as $row) {
            $rows[] = $this->mapRow(
                'purchase_order',
                'Purchase Order',
                (int) $row['id'],
                (string) $row['number'],
                (string) ($row['supplier_name'] ?: '—'),
                (string) ($row['order_date'] ?? ''),
                (float) ($row['total'] ?? 0)
            );
        }

        usort($rows, static function (array $a, array $b): int {
            $dateCmp = strcmp($a['date'], $b['date']);
            if ($dateCmp !== 0) {
                return $dateCmp;
            }

            return $a['id'] <=> $b['id'];
        });

        return $rows;
    }

    public function approve(string $type, int $id, ?int $actingUserId): array
    {
        return match ($type) {
            'purchase_request'   => $this->purchaseRequestService->approve($id, $actingUserId),
            'rfq'                => $this->rfqService->approve($id, $actingUserId),
            'supplier_quotation' => $this->supplierQuotationService->approve($id, $actingUserId),
            'purchase_order'     => $this->purchaseOrderService->approve($id, $actingUserId),
            default              => ['success' => false, 'error' => 'Unknown document type.'],
        };
    }

    public function reject(string $type, int $id, string $reason, ?int $actingUserId): array
    {
        return match ($type) {
            'purchase_request'   => $this->purchaseRequestService->reject($id, $reason, $actingUserId),
            'rfq'                => $this->rfqService->reject($id, $reason, $actingUserId),
            'supplier_quotation' => $this->supplierQuotationService->reject($id, $reason, $actingUserId),
            'purchase_order'     => $this->purchaseOrderService->reject($id, $reason, $actingUserId),
            default              => ['success' => false, 'error' => 'Unknown document type.'],
        };
    }

    protected function mapRow(
        string $type,
        string $typeLabel,
        int $id,
        string $number,
        string $supplierOrDept,
        string $date,
        float $total
    ): array {
        return [
            'type'             => $type,
            'type_label'       => $typeLabel,
            'id'               => $id,
            'number'           => $number,
            'supplier_or_dept' => $supplierOrDept,
            'date'             => $date,
            'total'            => $total,
            'approve_path'     => 'procurement/approval-queue/approve',
            'reject_path'      => 'procurement/approval-queue/reject',
        ];
    }
}
