<?php
/**
 * Bank Reconciliation UI.
 *
 * Flow:
 *   /BankRecon                 → list of statements (all banks)
 *   /BankRecon/add             → import a new CSV
 *   /BankRecon/save            → POST target for the import form
 *   /BankRecon/view/{id}       → the reconciliation workbench for one stmt
 *   /BankRecon/match/{id}      → POST { journal_line_id } — creates a match
 *   /BankRecon/unmatch/{id}    → POST — clears a match
 *   /BankRecon/autoMatch/{id}  → POST — batch auto-match by amount+date
 *   /BankRecon/adjust/{id}     → POST { contra_account_id, narrative } — creates JE + matches
 *   /BankRecon/complete/{id}   → POST — locks the statement RECONCILED
 *   /BankRecon/voidStmt/{id}   → POST — soft-deletes the statement
 */
class BankReconController extends Controller
{
    public function indexAction($page = 1)
    {
        $page    = max(1, (int)$page);
        $perPage = defined('ROWS_PER_PAGE') ? ROWS_PER_PAGE : 20;

        $filters = [
            'bank_account_id' => (int)($_GET['bank_account_id'] ?? 0),
            'status'          => trim((string)($_GET['status'] ?? '')),
        ];

        $m = new BankStatements();
        $result = $m->listPaginated($page, $perPage, $filters);

        $qs      = http_build_query(array_filter($filters, fn($v) => $v !== '' && $v !== 0));
        $baseUrl = PROOT . 'BankRecon/index/';
        $pg      = Pagination::paginate($result['total'], $perPage, $page, $baseUrl);
        $pgHtml  = $pg['html'];
        if ($qs && $pgHtml) {
            $pgHtml = preg_replace('~href=\'([^\']+)\'~', "href='$1?" . htmlspecialchars($qs) . "'", $pgHtml);
        }

        $this->view->setLayout($this->roleLayout());
        $this->view->render('BankRecon/index', [
            'page_title' => 'Bank Reconciliation',
            'rows'       => $result['rows'],
            'total'      => $result['total'],
            'banks'      => $m->bankAccounts(),
            'filters'    => $filters,
            'pg_html'    => $pgHtml,
        ]);
    }

    public function addAction()
    {
        $m = new BankStatements();
        $this->view->setLayout($this->roleLayout());
        $this->view->render('BankRecon/add', [
            'page_title' => 'Import Bank Statement',
            'banks'      => $m->bankAccounts(),
            'form'       => [],
            'fb_msg'     => '',
        ]);
    }

    public function saveAction()
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon/add'); return; }

        $body = $_POST;

        // CSV file is mandatory
        if (empty($_FILES['csv']['name']) || $_FILES['csv']['error'] !== UPLOAD_ERR_OK) {
            $this->reAdd($body, 'CSV file is required.'); return;
        }
        $tmp = $_FILES['csv']['tmp_name'];
        $ext = strtolower(pathinfo((string)$_FILES['csv']['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, ['csv', 'txt', 'tsv'], true)) {
            $this->reAdd($body, 'Upload a .csv, .tsv, or .txt file.'); return;
        }
        if ((int)$_FILES['csv']['size'] > 8 * 1024 * 1024) {
            $this->reAdd($body, 'CSV is larger than 8 MB — split it.'); return;
        }

        $m = new BankStatements();
        $parsed = $m->parseCsv($tmp);
        if (!$parsed['ok']) { $this->reAdd($body, $parsed['msg']); return; }

        $r = $m->createFromCsv($body, $parsed['rows'], $this->currentUserId());
        if (!$r['ok']) { $this->reAdd($body, $r['msg']); return; }

        $_SESSION['flash_tenant_msg']  = $r['msg'];
        $_SESSION['flash_tenant_type'] = 'success';
        Router::redirect('BankRecon/view/' . $r['id']);
    }

    public function viewAction($id = 0)
    {
        $stmts = new BankStatements();
        $s     = $stmts->byId((int)$id);
        if (!$s) { $this->notFound('Statement'); return; }

        $rec = new BankReconciler();
        $sum = $rec->summary((int)$id);

        $this->view->setLayout($this->roleLayout());
        $this->view->render('BankRecon/view', [
            'page_title'  => 'Reconcile · ' . $s['account_code'] . ' ' . humanDate($s['statement_from']) . '→' . humanDate($s['statement_to']),
            's'           => $s,
            'sum'         => $sum,
            'stmt_lines'  => $stmts->linesFor((int)$id),
            'book_lines'  => $stmts->bookLinesFor((int)$id),
            'suggestions' => $rec->autoSuggest((int)$id),
        ]);
    }

    public function matchAction($id = 0)
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon'); return; }

        $jl = (int)($_POST['journal_line_id'] ?? 0);
        $r  = (new BankReconciler())->match((int)$id, $jl, $this->currentUserId());

        $stmt = $this->parentStatementId((int)$id);
        $this->flashAndBack($r, $stmt);
    }

    public function unmatchAction($id = 0)
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon'); return; }

        $stmt = $this->parentStatementId((int)$id);
        $r    = (new BankReconciler())->unmatch((int)$id, $this->currentUserId());
        $this->flashAndBack($r, $stmt);
    }

    public function autoMatchAction($id = 0)
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon/view/' . (int)$id); return; }

        $n = (new BankReconciler())->applyAutoSuggestions((int)$id, $this->currentUserId());
        $_SESSION['flash_tenant_msg']  = "Auto-matched $n line(s).";
        $_SESSION['flash_tenant_type'] = $n > 0 ? 'success' : 'info';
        Router::redirect('BankRecon/view/' . (int)$id);
    }

    public function adjustAction($id = 0)
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon'); return; }

        $contra    = (int)($_POST['contra_account_id'] ?? 0);
        $narrative = trim((string)($_POST['narrative'] ?? ''));
        if ($contra <= 0)      { $this->flashBackToParent($id, ['ok' => false, 'msg' => 'Pick a contra account.']); return; }
        if ($narrative === '') { $this->flashBackToParent($id, ['ok' => false, 'msg' => 'Narrative is required.']); return; }

        $r = (new BankReconciler())->adjust(
            (int)$id, $contra, $narrative,
            $this->currentUserId(), $_SESSION['full_name'] ?? ''
        );
        $stmt = $this->parentStatementId((int)$id);
        $this->flashAndBack($r, $stmt);
    }

    public function completeAction($id = 0)
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon/view/' . (int)$id); return; }

        $r = (new BankReconciler())->complete((int)$id, $this->currentUserId());
        $_SESSION['flash_tenant_msg']  = $r['msg'];
        $_SESSION['flash_tenant_type'] = $r['ok'] ? 'success' : 'danger';
        Router::redirect('BankRecon/view/' . (int)$id);
    }

    public function voidStmtAction($id = 0)
    {
        $this->verifyCsrf();
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { Router::redirect('BankRecon/view/' . (int)$id); return; }

        (new BankStatements())->voidStatement((int)$id, $this->currentUserId());
        $_SESSION['flash_tenant_msg']  = 'Statement voided.';
        $_SESSION['flash_tenant_type'] = 'success';
        Router::redirect('BankRecon');
    }

    /* ── helpers ───────────────────────────────────────────────────── */

    private function reAdd(array $body, string $err): void
    {
        $m = new BankStatements();
        $this->view->setLayout($this->roleLayout());
        $this->view->render('BankRecon/add', [
            'page_title' => 'Import Bank Statement',
            'banks'      => $m->bankAccounts(),
            'form'       => $body,
            'fb_msg'     => '<div class="alert alert-danger">' . htmlspecialchars($err) . '</div>',
        ]);
    }

    /** Given a statement-line id, return its parent statement id (for redirects). */
    private function parentStatementId(int $stmtLineId): int
    {
        $db = new DB();
        $rs = $db->mySelect(
            'SELECT statement_id FROM bank_statement_lines WHERE c0d = :id',
            [':id' => $stmtLineId]
        );
        return (int)($rs[0]['statement_id'] ?? 0);
    }

    private function flashAndBack(array $r, int $stmtId): void
    {
        $_SESSION['flash_tenant_msg']  = $r['msg'];
        $_SESSION['flash_tenant_type'] = $r['ok'] ? 'success' : 'danger';
        if ($stmtId > 0) Router::redirect('BankRecon/view/' . $stmtId);
        else             Router::redirect('BankRecon');
    }

    private function flashBackToParent(int $stmtLineId, array $r): void
    {
        $this->flashAndBack($r, $this->parentStatementId($stmtLineId));
    }

    private function notFound(string $what): void
    {
        $this->view->setLayout($this->roleLayout());
        $this->view->render('generals/fb_page', [
            'page_title' => 'Not found',
            'fb_msg'     => '<div class="alert alert-danger">' . htmlspecialchars($what) . ' not found.</div>',
        ]);
    }
}
