<?php
/**
 * ServiceRequisitionsController — the full requisition surface (draft → issue).
 *
 * Slice 8b-4b adds the surfaces to what Slice 8b-4a built as the model spine.
 *
 *   /ServiceRequisitions                       list all (admin/dashboard)
 *   /ServiceRequisitions/myQueue               role-specific queue (Accountant sees APPROVED)
 *   /ServiceRequisitions/create/{project_id}   PC drafts a new requisition
 *   /ServiceRequisitions/view/{id}             detail with lines + chain history + issue action
 *   /ServiceRequisitions/addLineAj             POST req_id + category + description + qty + unit_cost
 *   /ServiceRequisitions/deleteLineAj          POST id
 *   /ServiceRequisitions/submitAj              POST id → chain
 *   /ServiceRequisitions/cancelAj              POST id (DRAFT only)
 *   /ServiceRequisitions/issueAj               POST id + issue_reference + issue_amount + notes  (Accountant)
 */
class ServiceRequisitionsController extends Controller
{
    public function indexAction()
    {
        $status = (string)($_GET['status'] ?? '');
        $rows = (new ServiceRequisitions())->listAll($status);
        $this->view->setLayout($this->roleLayout());
        $this->view->render('ServiceRequisitions/index', [
            'page_title' => 'Service Requisitions',
            'rows'       => $rows,
            'status'     => $status,
        ]);
    }

    public function myQueueAction()
    {
        $m = new ServiceRequisitions();
        $group = strtoupper((string)($_SESSION['user_group_name'] ?? ''));
        $userId = $this->currentUserId();

        // Accountant/FM/Admin get combined queues: issue queue + retirement review queue + close (GL) queue.
        // Others (PC etc) see their own requisitions.
        if (in_array($group, ['ACCOUNTANT','FINANCE MANAGER','ADMINISTRATOR'], true)) {
            $issueRows  = $m->openForAccountant();
            $retireRows = $m->openRetirementForAccountant();
            $closeRows  = $m->openCloseForAccountant();
            $this->view->setLayout($this->roleLayout());
            $this->view->render('ServiceRequisitions/myQueue', [
                'page_title'  => 'Requisition Queues',
                'issue_rows'  => $issueRows,
                'retire_rows' => $retireRows,
                'close_rows'  => $closeRows,
                'mode'        => 'accountant',
            ]);
            return;
        }
        $rows = $m->myRequisitions($userId, (string)($_GET['status'] ?? ''));
        $this->view->setLayout($this->roleLayout());
        $this->view->render('ServiceRequisitions/myQueue', [
            'page_title' => 'My Requisitions',
            'rows'       => $rows,
            'mode'       => 'mine',
        ]);
    }

    public function createAction($projectId = 0)
    {
        $projectId = (int)$projectId;
        $db = new DB();
        $prj = $db->mySelect(
            "SELECT c0d, project_no, project_name, project_type, project_customer, currency
               FROM c_projects WHERE c0d = :p AND deleted = 0",
            [':p' => $projectId]
        );
        if (empty($prj)) {
            $this->view->setLayout($this->roleLayout());
            $this->view->render('generals/fb_page', ['fb_msg' => '<div class="alert alert-danger">Project not found.</div>']);
            return;
        }
        $existing = (new ServiceRequisitions())->listForProject($projectId);
        $this->view->setLayout($this->roleLayout());
        $this->view->render('ServiceRequisitions/create', [
            'page_title' => 'New Requisition · ' . ($prj[0]['project_no'] ?? ''),
            'project'    => $prj[0],
            'existing'   => $existing,
        ]);
    }

    public function viewAction($id = 0)
    {
        $id = (int)$id;
        $m = new ServiceRequisitions();
        $req = $m->findById($id);
        if (!$req) {
            $this->view->setLayout($this->roleLayout());
            $this->view->render('generals/fb_page', ['fb_msg' => '<div class="alert alert-danger">Requisition not found.</div>']);
            return;
        }
        $db = new DB();
        $prj = $db->mySelect("SELECT c0d, project_no, project_name FROM c_projects WHERE c0d = :p", [':p' => (int)$req['project_id']]);
        $lines = $m->linesFor($id);
        $byCat = $m->linesByCategory($id);

        // Chain history
        $approval = []; $history = []; $steps = [];
        if ((int)$req['approval_id'] > 0) {
            if (!class_exists('ApprovalChain')) require_once ROOT . '/app/models/ApprovalChain.php';
            $ac = new ApprovalChain();
            $approval = $ac->approvalById((int)$req['approval_id']);
            $history  = $ac->historyFor((int)$req['approval_id']);
            if (!empty($approval)) $steps = $ac->stepsForChain((int)$approval['chain_id']);
        }

        $group = strtoupper((string)($_SESSION['user_group_name'] ?? ''));
        $currentUserId = $this->currentUserId();
        $isCreator = (int)$req['created_by'] === $currentUserId;
        $canEdit   = $req['status'] === 'DRAFT' && ($isCreator || in_array($group, ['ADMINISTRATOR'], true));
        $canSubmit = $req['status'] === 'DRAFT' && count($lines) > 0 && (float)$req['total_amount'] > 0
                     && ($isCreator || in_array($group, ['ADMINISTRATOR'], true));
        $canCancel = $req['status'] === 'DRAFT' && ($isCreator || in_array($group, ['ADMINISTRATOR'], true));
        $canIssue  = $req['status'] === 'APPROVED' && ServiceRequisitions::canIssue($group);

        // Retirement action gates
        $canStartRetirement  = $req['status'] === 'ISSUED' && ($isCreator || $group === 'ADMINISTRATOR');
        $canEditExpenses     = $req['status'] === 'RETIRING' && empty($req['retirement_submitted_on']) && $isCreator;
        $canSubmitRetirement = $canEditExpenses && count($m->expensesFor($id)) > 0;
        $canApproveRetire    = $req['status'] === 'RETIRING' && !empty($req['retirement_submitted_on'])
                                && ServiceRequisitions::canApproveRetirement($group);
        $canClose            = $req['status'] === 'RETIRED' && (int)$req['journal_entry_id'] === 0
                                && ServiceRequisitions::canClose($group);

        // Expense data (only load if we're at/past retirement start)
        $expenses = []; $expenseByCat = [];
        if (in_array($req['status'], ['RETIRING','RETIRED','CLOSED'], true)) {
            $expenses     = $m->expensesFor($id);
            $expenseByCat = $m->expensesByCategory($id);
        }

        // Bank picker for the close dialog (Accountant only sees this in RETIRED state)
        $banks = [];
        if ($canClose) {
            $banks = $db->mySelect(
                "SELECT c0d, account_name, bank_name, currency FROM bank_accounts WHERE is_active = 1 ORDER BY c0d",
                []
            ) ?: [];
        }

        // If CLOSED, hydrate the JE reference so the view can link to it
        $je = null;
        if ((int)$req['journal_entry_id'] > 0) {
            $je = $db->mySelect(
                "SELECT c0d, je_no, entry_date, total_debit, total_credit FROM journal_entries WHERE c0d = :id",
                [':id' => (int)$req['journal_entry_id']]
            );
            $je = $je[0] ?? null;
        }

        $this->view->setLayout($this->roleLayout());
        $this->view->render('ServiceRequisitions/view', [
            'page_title'    => $req['req_no'] . ' · ' . $req['title'],
            'req'           => $req,
            'project'       => $prj[0] ?? [],
            'lines'         => $lines,
            'by_category'   => $byCat,
            'categories'    => ServiceRequisitions::CATEGORIES,
            'approval'      => $approval,
            'history'       => $history,
            'steps'         => $steps,
            'can_edit'      => $canEdit,
            'can_submit'    => $canSubmit,
            'can_cancel'    => $canCancel,
            'can_issue'     => $canIssue,
            'can_start_retirement'  => $canStartRetirement,
            'can_edit_expenses'     => $canEditExpenses,
            'can_submit_retirement' => $canSubmitRetirement,
            'can_approve_retire'    => $canApproveRetire,
            'can_close'             => $canClose,
            'expenses'              => $expenses,
            'expense_by_category'   => $expenseByCat,
            'banks'                 => $banks,
            'je'                    => $je,
        ]);
    }

    /* ── AJAX endpoints ─────────────────────────────────────────────── */

    public function createAjAction()
    {
        header('Content-Type: application/json');
        try {
            $id = (new ServiceRequisitions())->draft(
                (int)($_POST['project_id'] ?? 0),
                [
                    'title'       => (string)($_POST['title'] ?? ''),
                    'purpose'     => (string)($_POST['purpose'] ?? ''),
                    'currency'    => (string)($_POST['currency'] ?? 'TZS'),
                    'context_ref' => (string)($_POST['context_ref'] ?? ''),
                ],
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? '')
            );
            echo json_encode(['ok' => true, 'id' => $id]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function addLineAjAction()
    {
        header('Content-Type: application/json');
        try {
            $id = (new ServiceRequisitions())->addLine(
                (int)($_POST['req_id'] ?? 0),
                (string)($_POST['category'] ?? 'MISC'),
                [
                    'description' => (string)($_POST['description'] ?? ''),
                    'qty'         => (float) ($_POST['qty'] ?? 1),
                    'unit'        => (string)($_POST['unit'] ?? ''),
                    'unit_cost'   => (float) ($_POST['unit_cost'] ?? 0),
                    'notes'       => (string)($_POST['notes'] ?? ''),
                ]
            );
            echo json_encode(['ok' => true, 'id' => $id]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function deleteLineAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->deleteLine((int)($_POST['id'] ?? 0));
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function submitAjAction()
    {
        header('Content-Type: application/json');
        try {
            $res = (new ServiceRequisitions())->submitForApproval(
                (int)($_POST['id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? ''),
                (string)($_SESSION['user_group_name'] ?? '')
            );
            echo json_encode($res);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function cancelAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->cancel((int)($_POST['id'] ?? 0), (int)($_SESSION['user_id'] ?? 0));
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function issueAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->issue(
                (int)($_POST['id'] ?? 0),
                [
                    'issue_reference' => (string)($_POST['issue_reference'] ?? ''),
                    'issue_amount'    => $_POST['issue_amount'] ?? '',
                    'issue_notes'     => (string)($_POST['issue_notes'] ?? ''),
                ],
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? ''),
                (string)($_SESSION['user_group_name'] ?? '')
            );
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    /* ── Slice 8b-4c · Retirement AJAX endpoints ────────────────────── */

    public function startRetirementAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->startRetirement(
                (int)($_POST['id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['user_group_name'] ?? '')
            );
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function addExpenseAjAction()
    {
        header('Content-Type: application/json');
        try {
            $id = (new ServiceRequisitions())->addExpense(
                (int)($_POST['req_id'] ?? 0),
                (string)($_POST['category'] ?? 'MISC'),
                [
                    'description'  => (string)($_POST['description'] ?? ''),
                    'amount'       => (float) ($_POST['amount'] ?? 0),
                    'receipt_ref'  => (string)($_POST['receipt_ref'] ?? ''),
                    'receipt_date' => (string)($_POST['receipt_date'] ?? ''),
                    'notes'        => (string)($_POST['notes'] ?? ''),
                ],
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? '')
            );
            echo json_encode(['ok' => true, 'id' => $id]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function deleteExpenseAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->deleteExpense(
                (int)($_POST['id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0)
            );
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function submitRetirementAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->submitRetirement(
                (int)($_POST['id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? '')
            );
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function approveRetirementAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->approveRetirement(
                (int)($_POST['id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? ''),
                (string)($_SESSION['user_group_name'] ?? ''),
                (string)($_POST['notes'] ?? '')
            );
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    public function sendBackRetirementAjAction()
    {
        header('Content-Type: application/json');
        try {
            (new ServiceRequisitions())->sendBackRetirement(
                (int)($_POST['id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? ''),
                (string)($_SESSION['user_group_name'] ?? ''),
                (string)($_POST['reason'] ?? '')
            );
            echo json_encode(['ok' => true]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }

    /* ── Slice 8b-4d · Close (GL post) ───────────────────────────────── */

    public function closeAjAction()
    {
        header('Content-Type: application/json');
        try {
            $jeId = (new ServiceRequisitions())->close(
                (int)($_POST['id'] ?? 0),
                (int)($_POST['bank_account_id'] ?? 0),
                (int)($_SESSION['user_id'] ?? 0),
                (string)($_SESSION['full_name'] ?? ''),
                (string)($_SESSION['user_group_name'] ?? '')
            );
            echo json_encode(['ok' => true, 'je_id' => $jeId]);
        } catch (Throwable $e) { echo json_encode(['ok' => false, 'msg' => $e->getMessage()]); }
    }
}
