<?php

namespace Modules\Operations\Services;

use App\Models\ExpenseModel;
use App\Models\LeaveRequestModel;
use App\Models\LeaveTypeModel;
use App\Models\EmployeeModel;
use App\Models\WorkOrderModel;
use Modules\Accounting\Services\ExpenseService;
use Modules\Leave\Services\LeaveRequestService;
use Modules\Procurement\Services\ApprovalQueueService as ProcurementApprovalQueueService;

class OperationsApprovalService
{
    protected ExpenseModel $expenses;
    protected WorkOrderModel $workOrders;
    protected LeaveRequestModel $leaveRequests;
    protected LeaveTypeModel $leaveTypes;
    protected EmployeeModel $employees;

    protected ExpenseService $expenseService;
    protected WorkOrderService $workOrderService;
    protected LeaveRequestService $leaveRequestService;
    protected ProcurementApprovalQueueService $procurementQueue;

    public function __construct()
    {
        $this->expenses      = new ExpenseModel();
        $this->workOrders    = new WorkOrderModel();
        $this->leaveRequests = new LeaveRequestModel();
        $this->leaveTypes    = new LeaveTypeModel();
        $this->employees     = new EmployeeModel();

        $this->expenseService      = new ExpenseService();
        $this->workOrderService    = new WorkOrderService();
        $this->leaveRequestService = new LeaveRequestService();
        $this->procurementQueue    = new ProcurementApprovalQueueService();
    }

    /**
     * @return list<array>
     */
    public function listExpenses(?string $search = null): array
    {
        $rows = [];
        foreach ($this->expenses->scopeForList($search, 'draft')->orderBy('expense_date', 'ASC')->orderBy('id', 'ASC')->findAll() as $row) {
            $rows[] = [
                'type'         => 'expense',
                'type_label'   => 'Expense',
                'id'           => (int) $row['id'],
                'number'       => (string) $row['number'],
                'detail'       => (string) ($row['payee'] ?: ($row['account_name'] ?? '—')),
                'date'         => (string) ($row['expense_date'] ?? ''),
                'amount'       => (float) ($row['amount'] ?? 0),
                'approve_path' => 'operations/approvals/expenses/approve',
                'reject_path'  => null,
                'can_reject'   => false,
            ];
        }

        return $rows;
    }

    /**
     * @return list<array>
     */
    public function listWorkOrders(?string $search = null): array
    {
        $rows = [];
        foreach ($this->workOrders->scopeForList($search, 'pending_approval')->orderBy('due_date', 'ASC')->orderBy('id', 'ASC')->findAll() as $row) {
            $rows[] = [
                'type'         => 'work_order',
                'type_label'   => 'Work Order',
                'id'           => (int) $row['id'],
                'number'       => (string) $row['number'],
                'detail'       => (string) $row['title'],
                'date'         => (string) ($row['due_date'] ?? $row['scheduled_date'] ?? ''),
                'amount'       => null,
                'approve_path' => 'operations/approvals/work-orders/approve',
                'reject_path'  => 'operations/approvals/work-orders/reject',
                'can_reject'   => true,
            ];
        }

        return $rows;
    }

    /**
     * @return list<array>
     */
    public function listPurchases(?string $search = null): array
    {
        $rows = [];
        foreach ($this->procurementQueue->listPending($search) as $row) {
            $rows[] = [
                'type'         => $row['type'],
                'type_label'   => $row['type_label'],
                'id'           => $row['id'],
                'number'       => $row['number'],
                'detail'       => $row['supplier_or_dept'],
                'date'         => $row['date'],
                'amount'       => $row['total'],
                'approve_path' => 'operations/approvals/purchases/approve',
                'reject_path'  => 'operations/approvals/purchases/reject',
                'can_reject'   => true,
            ];
        }

        return $rows;
    }

    /**
     * @return list<array>
     */
    public function listLeave(?string $search = null): array
    {
        $employeeMap = [];
        foreach ($this->employees->findAll() as $e) {
            $employeeMap[(int) $e['id']] = $e['full_name'] ?? ('#' . $e['id']);
        }

        $typeMap = [];
        foreach ($this->leaveTypes->findAll() as $t) {
            $typeMap[(int) $t['id']] = $t['name'] ?? ('#' . $t['id']);
        }

        $builder = $this->leaveRequests->scopeForList($search, 'pending');
        $pending = $builder->orderBy('start_date', 'ASC')->orderBy('id', 'ASC')->findAll();

        $rows = [];
        foreach ($pending as $row) {
            $empName  = $employeeMap[(int) $row['employee_id']] ?? '—';
            $typeName = $typeMap[(int) $row['leave_type_id']] ?? 'Leave';
            $rows[] = [
                'type'         => 'leave_request',
                'type_label'   => 'Leave Request',
                'id'           => (int) $row['id'],
                'number'       => '#' . $row['id'],
                'detail'       => $empName . ' — ' . $typeName,
                'date'         => (string) ($row['start_date'] ?? ''),
                'amount'       => (float) ($row['days'] ?? 0),
                'approve_path' => 'operations/approvals/leave/approve',
                'reject_path'  => 'operations/approvals/leave/reject',
                'can_reject'   => true,
            ];
        }

        return $rows;
    }

    public function approveExpense(int $id, ?int $actingUserId): array
    {
        return $this->expenseService->approve($id, $actingUserId);
    }

    public function approveWorkOrder(int $id, ?int $actingUserId): array
    {
        return $this->workOrderService->approve($id, $actingUserId);
    }

    public function rejectWorkOrder(int $id, string $reason, ?int $actingUserId): array
    {
        return $this->workOrderService->reject($id, $reason, $actingUserId);
    }

    public function approvePurchase(string $type, int $id, ?int $actingUserId): array
    {
        return $this->procurementQueue->approve($type, $id, $actingUserId);
    }

    public function rejectPurchase(string $type, int $id, string $reason, ?int $actingUserId): array
    {
        return $this->procurementQueue->reject($type, $id, $reason, $actingUserId);
    }

    public function approveLeave(int $id, ?int $actingUserId): array
    {
        return $this->leaveRequestService->approve($id, $actingUserId);
    }

    public function rejectLeave(int $id, string $reason, ?int $actingUserId): array
    {
        return $this->leaveRequestService->reject($id, $reason, $actingUserId);
    }
}
