<?php
/**
 * Expense Controller — Petty Cash / Daily Expenses
 */

class ExpenseController {
    private PDO $db;
    private object $user;

    public function __construct(PDO $db, object $user) {
        $this->db = $db;
        $this->user = $user;
    }

    /** GET /expenses?from_date=2026-04-01&to_date=2026-04-30&item_id=1 */
    public function index(array $query): void {
        $fromDate = $query['from_date'] ?? ($query['date'] ?? date('Y-m-d'));
        $toDate = $query['to_date'] ?? $fromDate;

        $where = [
            "j.source_type = 'expense'",
            "j.is_reversed = 0",
            "j.narration NOT LIKE 'REVERSAL%'",
            "j.journal_date BETWEEN ? AND ?"
        ];
        $params = [$fromDate, $toDate];

        if (!empty($query['item_id'])) {
            $where[] = 'j.source_id = ?';
            $params[] = (int)$query['item_id'];
        }

        $whereSql = implode(' AND ', $where);

        $stmt = $this->db->prepare("
            SELECT j.id, j.journal_date, j.narration, j.total_amount, j.is_reversed, j.source_id as item_id,
                   u.full_name as created_by_name, i.name as item_name,
                   (SELECT account_id FROM journal_entries WHERE journal_id = j.id AND credit > 0 LIMIT 1) as account_id
            FROM journals j
            LEFT JOIN users u ON j.created_by = u.id
            LEFT JOIN items i ON j.source_id = i.id AND j.source_type = 'expense'
            WHERE {$whereSql}
            ORDER BY j.id DESC
        ");
        $stmt->execute($params);

        $expenses = $stmt->fetchAll();
        $total = array_sum(array_column($expenses, 'total_amount'));

        Response::success(['expenses' => $expenses, 'total' => $total]);
    }

    /** POST /expenses */
    public function store(array $data): void {
        Validator::check($data, [
            'date'       => 'required|date',
            'narration'  => 'required|string|max:500',
            'amount'     => 'required|numeric|positive',
            'account_id' => 'required|integer',
            'item_id'    => 'nullable|integer'
        ]);

        // Get system expense account
        $expenseAccStmt = $this->db->prepare("SELECT id FROM accounts WHERE is_system = 1 AND sub_type = 'expense' LIMIT 1");
        $expenseAccStmt->execute();
        $expenseAccId = (int)$expenseAccStmt->fetchColumn();

        $amount = floatval($data['amount']);
        $cashBankId = (int)$data['account_id'];
        $narration = $data['narration'];

        $entries = [
            ['account_id' => $expenseAccId, 'debit' => $amount, 'credit' => 0, 'narration' => $narration],
            ['account_id' => $cashBankId, 'debit' => 0, 'credit' => $amount, 'narration' => "خرچہ: {$narration}"]
        ];

        $this->db->beginTransaction();
        try {
            AccountingService::assertSufficientBankCashBalance($this->db, $cashBankId, $amount);

            $itemId = !empty($data['item_id']) ? (int)$data['item_id'] : null;
            
            $journalId = AccountingService::postJournal($this->db, [
                'date'        => $data['date'],
                'source_type' => 'expense',
                'source_id'   => $itemId,
                'narration'   => "خرچہ: {$narration}",
                'created_by'  => $this->user->id
            ], $entries);

            AuditLogger::log($this->db, $this->user->id, 'CREATED_EXPENSE', 'journals', $journalId, null, $data);

            $this->db->commit();
            Response::created(['id' => $journalId], 'خرچہ ریکارڈ ہو گیا۔');
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    /** PUT /expenses/{id} */
    public function update(int $id, array $data): void {
        Validator::check($data, [
            'date'       => 'required|date',
            'narration'  => 'required|string|max:500',
            'amount'     => 'required|numeric|positive',
            'account_id' => 'required|integer',
            'item_id'    => 'nullable|integer'
        ]);

        $stmt = $this->db->prepare("SELECT * FROM journals WHERE id = ? AND source_type = 'expense'");
        $stmt->execute([$id]);
        $old = $stmt->fetch();
        if (!$old) Response::notFound('خرچہ نہیں ملا۔');
        if ($old['is_reversed']) Response::conflict('ریورس شدہ خرچہ میں تبدیلی نہیں کی جا سکتی۔');

        // Get system expense account
        $expenseAccStmt = $this->db->prepare("SELECT id FROM accounts WHERE is_system = 1 AND sub_type = 'expense' LIMIT 1");
        $expenseAccStmt->execute();
        $expenseAccId = (int)$expenseAccStmt->fetchColumn();

        $amount = floatval($data['amount']);
        $cashBankId = (int)$data['account_id'];
        $narration = $data['narration'];

        $entries = [
            ['account_id' => $expenseAccId, 'debit' => $amount, 'credit' => 0, 'narration' => $narration],
            ['account_id' => $cashBankId, 'debit' => 0, 'credit' => $amount, 'narration' => "خرچہ: {$narration}"]
        ];

        $this->db->beginTransaction();
        try {
            // Reverse old expense journal
            AccountingService::reverseJournal($this->db, $id, $this->user->id);
            AccountingService::assertSufficientBankCashBalance($this->db, $cashBankId, $amount);

            // Post new journal
            $itemId = !empty($data['item_id']) ? (int)$data['item_id'] : null;
            $newJournalId = AccountingService::postJournal($this->db, [
                'date'        => $data['date'],
                'source_type' => 'expense',
                'source_id'   => $itemId,
                'narration'   => "تصحیح خرچہ: {$narration}",
                'created_by'  => $this->user->id
            ], $entries);

            AuditLogger::log($this->db, $this->user->id, 'UPDATED_EXPENSE', 'journals', $id, $old, $data);

            $this->db->commit();
            Response::success(['id' => $newJournalId], 'خرچہ اپڈیٹ ہو گیا۔');
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    /** DELETE /expenses/{id} */
    public function destroy(int $id): void {
        $stmt = $this->db->prepare("SELECT * FROM journals WHERE id = ? AND source_type = 'expense'");
        $stmt->execute([$id]);
        $old = $stmt->fetch();
        if (!$old) Response::notFound('خرچہ نہیں ملا۔');
        if ($old['is_reversed']) Response::conflict('خرچہ پہلے ہی حذف (ریورس) ہو چکا ہے۔');

        $this->db->beginTransaction();
        try {
            AccountingService::reverseJournal($this->db, $id, $this->user->id);
            AuditLogger::log($this->db, $this->user->id, 'DELETED_EXPENSE', 'journals', $id, $old);
            $this->db->commit();
            Response::success(null, 'خرچہ کامیابی سے حذف ہو گیا۔');
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }
}
