<?php

class GLController extends Controller
{
    public function accounts(Request $request): void
    {
        $db = $this->db();
        $accounts = $db->fetchAll("SELECT * FROM gl_accounts WHERE is_active = 1 ORDER BY account_code");
        $tree = $this->buildTree($accounts);

        $this->view('gl/accounts', [
            'title' => lang('adv_finance.chart_of_accounts'),
            'breadcrumbs' => [['label' => lang('adv_finance.gl'), 'url' => '/advanced-finance/gl'], ['label' => lang('adv_finance.chart_of_accounts')]],
            'accounts' => $accounts,
            'tree' => $tree,
        ], 'app');
    }

    private function buildTree(array $accounts, ?int $parentId = null): array
    {
        $branch = [];
        foreach ($accounts as $a) {
            if ($a['parent_id'] == $parentId) {
                $a['children'] = $this->buildTree($accounts, $a['id']);
                $branch[] = $a;
            }
        }
        return $branch;
    }

    public function accountsDatatable(Request $request): void
    {
        $db = $this->db();
        $draw = (int)$request->get('draw', 1);
        $start = (int)$request->get('start', 0);
        $length = (int)$request->get('length', 50);
        $search = $request->get('search')['value'] ?? '';

        $where = 'is_active = 1'; $params = [];
        if ($search) { $where .= ' AND (account_code LIKE ? OR name_en LIKE ? OR name_ar LIKE ?)'; $like = "%{$search}%"; $params = [$like,$like,$like]; }

        $total = (int)$db->fetchColumn("SELECT COUNT(*) FROM gl_accounts WHERE is_active = 1");
        $filtered = (int)$db->fetchColumn("SELECT COUNT(*) FROM gl_accounts WHERE {$where}", $params);
        $rows = $db->fetchAll("SELECT * FROM gl_accounts WHERE {$where} ORDER BY account_code LIMIT {$length} OFFSET {$start}", $params);

        $data = [];
        foreach ($rows as $r) {
            $data[] = [
                'id' => $r['id'], 'account_code' => $r['account_code'],
                'name_en' => $r['name_en'], 'name_ar' => $r['name_ar'],
                'account_type' => ucfirst($r['account_type']), 'normal_balance' => ucfirst($r['normal_balance']),
                'is_header' => $r['is_header'] ? '<span class="badge bg-info">Header</span>' : '<span class="badge bg-secondary">Postable</span>',
                'level' => $r['level'],
            ];
        }
        $this->json(['draw' => $draw, 'recordsTotal' => $total, 'recordsFiltered' => $filtered, 'data' => $data]);
    }

    public function journalEntries(Request $request): void
    {
        $this->view('gl/journal-entries', [
            'title' => lang('adv_finance.journal_entries'),
            'breadcrumbs' => [['label' => lang('adv_finance.gl'), 'url' => '/advanced-finance/gl'], ['label' => lang('adv_finance.journal_entries')]],
        ], 'app');
    }

    public function journalEntriesDatatable(Request $request): void
    {
        $db = $this->db();
        $draw = (int)$request->get('draw', 1);
        $start = (int)$request->get('start', 0);
        $length = (int)$request->get('length', 25);
        $search = $request->get('search')['value'] ?? '';

        $where = '1=1'; $params = [];
        if ($search) { $where .= ' AND (je.journal_number LIKE ? OR je.description_en LIKE ?)'; $like = "%{$search}%"; $params = [$like,$like]; }
        $sf = $request->get('status_filter', '');
        if ($sf) { $where .= ' AND je.status = ?'; $params[] = $sf; }

        $total = (int)$db->fetchColumn("SELECT COUNT(*) FROM gl_journal_entries je");
        $filtered = (int)$db->fetchColumn("SELECT COUNT(*) FROM gl_journal_entries je WHERE {$where}", $params);
        $rows = $db->fetchAll(
            "SELECT je.* FROM gl_journal_entries je WHERE {$where} ORDER BY je.id DESC LIMIT {$length} OFFSET {$start}",
            $params
        );
        $data = [];
        foreach ($rows as $r) {
            $data[] = [
                'id' => $r['id'], 'journal_number' => $r['journal_number'],
                'entry_date' => format_date($r['entry_date']),
                'description' => str_limit($r['description_en'], 60),
                'total_debit' => format_money($r['total_debit']),
                'total_credit' => format_money($r['total_credit']),
                'status' => $r['status'], 'status_badge' => status_badge($r['status']),
            ];
        }
        $this->json(['draw' => $draw, 'recordsTotal' => $total, 'recordsFiltered' => $filtered, 'data' => $data]);
    }

    public function createJournalEntry(Request $request): void
    {
        $db = $this->db();
        $accounts = $db->fetchAll("SELECT id, account_code, name_en, name_ar FROM gl_accounts WHERE is_active = 1 AND is_postable = 1 ORDER BY account_code");
        $fiscalYears = $db->fetchAll("SELECT * FROM fiscal_years WHERE status = 'open'");

        $this->view('gl/journal-entry-form', [
            'title' => lang('common.create') . ' ' . lang('adv_finance.journal_entries'),
            'breadcrumbs' => [['label' => lang('adv_finance.journal_entries'), 'url' => '/advanced-finance/gl/journal-entries'], ['label' => lang('common.create')]],
            'accounts' => $accounts, 'fiscalYears' => $fiscalYears, 'entry' => null,
        ], 'app');
    }

    public function storeJournalEntry(Request $request): void
    {
        if (!CSRF::validate($request->csrfToken())) { $this->json(['success' => false, 'message' => 'Invalid CSRF'], 403); return; }

        $validator = new Validator($request->all(), [
            'entry_date'     => 'required|date',
            'description_en' => 'required|string|max:500',
            'description_ar' => 'nullable|string|max:500',
        ]);
        if ($validator->fails()) { $this->json(['success' => false, 'errors' => $validator->errors()], 422); return; }
        $d = $validator->validated();

        $lines = $request->post('lines', []);
        if (!is_array($lines) || count($lines) < 2) {
            $this->json(['success' => false, 'message' => 'At least 2 lines required'], 422);
            return;
        }

        $totalDebit = 0; $totalCredit = 0;
        foreach ($lines as $line) {
            $totalDebit += (float)($line['debit_amount'] ?? 0);
            $totalCredit += (float)($line['credit_amount'] ?? 0);
        }

        if (abs($totalDebit - $totalCredit) > 0.01) {
            $this->json(['success' => false, 'message' => 'Debits must equal credits. Debit: ' . format_money($totalDebit) . ', Credit: ' . format_money($totalCredit)], 422);
            return;
        }

        $db = $this->db();
        $fy = $db->fetchOne("SELECT id FROM fiscal_years WHERE status = 'open' AND start_date <= ? AND end_date >= ? LIMIT 1", [$d['entry_date'], $d['entry_date']]);
        $fp = null;
        if ($fy) {
            $fp = $db->fetchOne("SELECT id FROM fiscal_periods WHERE fiscal_year_id = ? AND status = 'open' AND start_date <= ? AND end_date >= ? LIMIT 1", [$fy['id'], $d['entry_date'], $d['entry_date']]);
        }

        $jnNumber = SequenceGenerator::next('journal_number');

        try {
            $db->beginTransaction();
            $jeId = $db->insert('gl_journal_entries', [
                'journal_number'  => $jnNumber,
                'entry_date'      => $d['entry_date'],
                'fiscal_year_id'  => $fy['id'] ?? null,
                'fiscal_period_id'=> $fp['id'] ?? null,
                'description_en'  => $d['description_en'],
                'description_ar'  => $d['description_ar'] ?? null,
                'total_debit'     => $totalDebit,
                'total_credit'    => $totalCredit,
                'status'          => 'draft',
                'created_by'      => Auth::id(),
            ]);

            $lineNum = 1;
            foreach ($lines as $line) {
                if (empty($line['account_id'])) continue;
                $db->insert('gl_journal_entry_lines', [
                    'journal_entry_id' => $jeId,
                    'line_number'      => $lineNum++,
                    'account_id'       => (int)$line['account_id'],
                    'description'      => $line['description'] ?? null,
                    'debit_amount'     => (float)($line['debit_amount'] ?? 0),
                    'credit_amount'    => (float)($line['credit_amount'] ?? 0),
                    'member_id'        => !empty($line['member_id']) ? (int)$line['member_id'] : null,
                    'department_id'    => !empty($line['department_id']) ? (int)$line['department_id'] : null,
                ]);
            }

            $db->commit();
            $this->audit('create', 'gl_journal_entries', $jeId, 'Created journal entry ' . $jnNumber);
            $this->json(['success' => true, 'message' => lang('adv_finance.saved'), 'redirect' => '/advanced-finance/gl/journal-entries/' . $jeId]);
        } catch (\Exception $e) {
            $db->rollBack();
            Logger::error('JE creation failed: ' . $e->getMessage());
            $this->json(['success' => false, 'message' => 'Failed to create entry'], 500);
        }
    }

    public function showJournalEntry(Request $request): void
    {
        $id = (int)$request->routeParam('id');
        $db = $this->db();
        $je = $db->fetchOne("SELECT * FROM gl_journal_entries WHERE id = ?", [$id]);
        if (!$je) { $this->abort(404, 'Not found'); return; }
        $lines = $db->fetchAll(
            "SELECT jel.*, ga.account_code, ga.name_en AS account_name
             FROM gl_journal_entry_lines jel
             JOIN gl_accounts ga ON jel.account_id = ga.id
             WHERE jel.journal_entry_id = ?
             ORDER BY jel.line_number",
            [$id]
        );
        $this->view('gl/journal-entry-show', [
            'title' => $je['journal_number'],
            'breadcrumbs' => [['label' => lang('adv_finance.journal_entries'), 'url' => '/advanced-finance/gl/journal-entries'], ['label' => $je['journal_number']]],
            'je' => $je, 'lines' => $lines,
        ], 'app');
    }

    public function postJournalEntry(Request $request): void
    {
        if (!CSRF::validate($request->csrfToken())) { $this->json(['success' => false, 'message' => 'Invalid CSRF'], 403); return; }
        $id = (int)$request->routeParam('id');
        $db = $this->db();
        $je = $db->fetchOne("SELECT * FROM gl_journal_entries WHERE id = ? AND status = 'draft'", [$id]);
        if (!$je) { $this->json(['success' => false, 'message' => 'Cannot post — not draft'], 422); return; }

        $db->update('gl_journal_entries', [
            'status' => 'posted', 'posted_by' => Auth::id(), 'posted_at' => date('Y-m-d H:i:s'),
        ], 'id = ?', [$id]);

        $this->audit('update', 'gl_journal_entries', $id, 'Posted journal entry ' . $je['journal_number']);
        $this->json(['success' => true, 'message' => lang('adv_finance.posted'), 'redirect' => '/advanced-finance/gl/journal-entries/' . $id]);
    }

    public function reverseJournalEntry(Request $request): void
    {
        if (!CSRF::validate($request->csrfToken())) { $this->json(['success' => false, 'message' => 'Invalid CSRF'], 403); return; }
        $id = (int)$request->routeParam('id');
        $db = $this->db();
        $je = $db->fetchOne("SELECT * FROM gl_journal_entries WHERE id = ? AND status = 'posted'", [$id]);
        if (!$je) { $this->json(['success' => false, 'message' => 'Cannot reverse — not posted'], 422); return; }

        $db->update('gl_journal_entries', [
            'status' => 'reversed', 'reversed_by' => Auth::id(), 'reversed_at' => date('Y-m-d H:i:s'),
        ], 'id = ?', [$id]);

        $this->audit('update', 'gl_journal_entries', $id, 'Reversed journal entry ' . $je['journal_number']);
        $this->json(['success' => true, 'message' => lang('adv_finance.reversed'), 'redirect' => '/advanced-finance/gl/journal-entries/' . $id]);
    }

    public function balances(Request $request): void
    {
        $db = $this->db();
        $fiscalYears = $db->fetchAll("SELECT * FROM fiscal_years ORDER BY start_date DESC");
        $selectedYear = (int)$request->get('fiscal_year_id', 0);
        $balances = [];
        if ($selectedYear) {
            $balances = $db->fetchAll(
                "SELECT gab.*, ga.account_code, ga.name_en, ga.name_ar, ga.account_type, fp.name_en AS period_name
                 FROM gl_account_balances gab
                 JOIN gl_accounts ga ON gab.account_id = ga.id
                 JOIN fiscal_periods fp ON gab.fiscal_period_id = fp.id
                 WHERE gab.fiscal_year_id = ?
                 ORDER BY ga.account_code, fp.period_number",
                [$selectedYear]
            );
        }
        $this->view('gl/balances', [
            'title' => lang('adv_finance.balances'),
            'breadcrumbs' => [['label' => lang('adv_finance.gl'), 'url' => '/advanced-finance/gl'], ['label' => lang('adv_finance.balances')]],
            'fiscalYears' => $fiscalYears, 'selectedYear' => $selectedYear, 'balances' => $balances,
        ], 'app');
    }
}