<?php
/**
 * Finance Module API
 * Handles bank accounts, transactions, and financial operations
 */

require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/db.php';

require_login();
header('Content-Type: application/json');

$mysqli = db();
$action = $_GET['action'] ?? $_POST['action'] ?? 'list';

// Helper function for CSRF verification
function verify_csrf() {
    $token = $_POST['csrf'] ?? '';
    if (empty($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $token)) {
        json_response(['message' => 'Invalid CSRF token'], 403);
    }
}

// Permission helper functions
function can_view_finance() {
    return has_role(['admin', 'super_admin', 'accountant', 'finance_manager']);
}

function can_edit_finance() {
    return has_role(['admin', 'super_admin', 'accountant']);
}

function can_approve_transactions() {
    return has_role(['admin', 'super_admin', 'finance_manager']);
}

// Schema Migration Function
function ensure_finance_schema(mysqli $db) {
    // Bank Accounts Table
    $db->query("CREATE TABLE IF NOT EXISTS bank_accounts (
        id INT AUTO_INCREMENT PRIMARY KEY,
        account_name VARCHAR(150) NOT NULL,
        account_number VARCHAR(50) NOT NULL UNIQUE,
        bank_name VARCHAR(100) DEFAULT NULL,
        branch_name VARCHAR(100) DEFAULT NULL,
        ifsc_code VARCHAR(20) DEFAULT NULL,
        swift_code VARCHAR(20) DEFAULT NULL,
        currency VARCHAR(3) NOT NULL DEFAULT 'LKR',
        initial_balance DECIMAL(15,2) NOT NULL DEFAULT 0.00,
        current_balance DECIMAL(15,2) NOT NULL DEFAULT 0.00,
        account_type ENUM('Current','Savings','Fixed Deposit','Recurring Deposit','Other') DEFAULT 'Current',
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        is_default TINYINT(1) NOT NULL DEFAULT 0,
        description TEXT,
        opening_date DATE DEFAULT NULL,
        created_by INT DEFAULT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        INDEX account_name (account_name),
        INDEX bank_name (bank_name),
        INDEX is_active (is_active)
    ) ENGINE=InnoDB");

    // Transactions Table
    $db->query("CREATE TABLE IF NOT EXISTS transactions (
        id INT AUTO_INCREMENT PRIMARY KEY,
        voucher_number VARCHAR(50) NOT NULL UNIQUE,
        transaction_date DATE NOT NULL,
        transaction_type ENUM('Receipt','Payment','Contra','Journal') NOT NULL,
        account_head VARCHAR(100) NOT NULL,
        sub_account_head VARCHAR(100) DEFAULT NULL,
        bank_account_id INT DEFAULT NULL,
        party_id INT DEFAULT NULL,
        party_type ENUM('Customer','Supplier','Employee','Other') DEFAULT NULL,
        party_name VARCHAR(150) DEFAULT NULL,
        amount DECIMAL(15,2) NOT NULL DEFAULT 0.00,
        amount_in_words VARCHAR(255) DEFAULT NULL,
        mode_of_payment ENUM('Cash','Cheque','Bank Transfer','Online Payment','Credit Card','Debit Card','Draft','Other') DEFAULT 'Cash',
        cheque_number VARCHAR(50) DEFAULT NULL,
        cheque_date DATE DEFAULT NULL,
        bank_name VARCHAR(100) DEFAULT NULL,
        narration TEXT,
        document_reference VARCHAR(100) DEFAULT NULL,
        document_date DATE DEFAULT NULL,
        cost_center VARCHAR(100) DEFAULT NULL,
        project_code VARCHAR(50) DEFAULT NULL,
        tax_amount DECIMAL(15,2) DEFAULT 0.00,
        tax_percent DECIMAL(5,2) DEFAULT 0.00,
        tax_type VARCHAR(50) DEFAULT NULL,
        is_reconciled TINYINT(1) NOT NULL DEFAULT 0,
        reconciled_date DATE DEFAULT NULL,
        reconciled_by INT DEFAULT NULL,
        is_approved TINYINT(1) NOT NULL DEFAULT 0,
        approved_by INT DEFAULT NULL,
        approved_at TIMESTAMP NULL,
        approval_status ENUM('Pending','Approved','Rejected') NOT NULL DEFAULT 'Pending',
        rejection_reason VARCHAR(255) DEFAULT NULL,
        entered_by INT DEFAULT NULL,
        entered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        modified_by INT DEFAULT NULL,
        modified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        is_cancelled TINYINT(1) NOT NULL DEFAULT 0,
        cancelled_by INT DEFAULT NULL,
        cancelled_at TIMESTAMP NULL,
        cancellation_reason VARCHAR(255) DEFAULT NULL,
        related_transaction_id INT DEFAULT NULL,
        reference_id INT DEFAULT NULL,
        reference_type VARCHAR(50) DEFAULT NULL,
        notes TEXT,
        INDEX transaction_date (transaction_date),
        INDEX transaction_type (transaction_type),
        INDEX account_head (account_head),
        INDEX bank_account_id (bank_account_id),
        INDEX party_id (party_id),
        INDEX is_reconciled (is_reconciled),
        INDEX is_approved (is_approved),
        INDEX approval_status (approval_status),
        INDEX is_cancelled (is_cancelled),
        CONSTRAINT fk_transaction_bank_account FOREIGN KEY (bank_account_id) REFERENCES bank_accounts(id) ON DELETE SET NULL
    ) ENGINE=InnoDB");

    // Transaction Attachments Table
    $db->query("CREATE TABLE IF NOT EXISTS transaction_attachments (
        id INT AUTO_INCREMENT PRIMARY KEY,
        transaction_id INT NOT NULL,
        file_name VARCHAR(255) NOT NULL,
        file_path VARCHAR(500) NOT NULL,
        file_type VARCHAR(50) DEFAULT NULL,
        file_size INT DEFAULT NULL,
        uploaded_by INT DEFAULT NULL,
        uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        description VARCHAR(255) DEFAULT NULL,
        INDEX transaction_id (transaction_id),
        CONSTRAINT fk_attachment_transaction FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE
    ) ENGINE=InnoDB");

    // Account Heads Table (Chart of Accounts)
    $db->query("CREATE TABLE IF NOT EXISTS account_heads (
        id INT AUTO_INCREMENT PRIMARY KEY,
        account_code VARCHAR(20) NOT NULL UNIQUE,
        account_name VARCHAR(150) NOT NULL,
        account_type ENUM('Asset','Liability','Income','Expense','Equity') NOT NULL,
        parent_id INT DEFAULT NULL,
        is_active TINYINT(1) NOT NULL DEFAULT 1,
        description TEXT,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX account_type (account_type),
        INDEX parent_id (parent_id)
    ) ENGINE=InnoDB");

    // Add columns if they don't exist (for backward compatibility)
    $check = $db->query("SHOW COLUMNS FROM bank_accounts LIKE 'swift_code'");
    if (!$check || !$check->fetch_assoc()) {
        $db->query("ALTER TABLE bank_accounts ADD COLUMN swift_code VARCHAR(20) DEFAULT NULL AFTER ifsc_code");
    }
}

// Run schema migration
ensure_finance_schema($mysqli);

// Generate voucher number helper
function generate_voucher_number($mysqli, $type, $date = null) {
    $date = $date ?? date('Y-m-d');
    $year = date('Y', strtotime($date));
    $month = date('m', strtotime($date));
    
    // Type prefix: RCP = Receipt, PMT = Payment, CTR = Contra, JNL = Journal
    $prefixes = [
        'Receipt' => 'RCP',
        'Payment' => 'PMT',
        'Contra' => 'CTR',
        'Journal' => 'JNL'
    ];
    $prefix = $prefixes[$type] ?? 'TXN';
    
    // Format: RCP-2025-000001
    $like = $prefix . '-' . $year . '-%';
    
    $stmt = $mysqli->prepare("SELECT voucher_number FROM transactions WHERE voucher_number LIKE ? ORDER BY id DESC LIMIT 1");
    $stmt->bind_param('s', $like);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    $stmt->close();
    
    $next = 1;
    if ($row && preg_match('/-' . $year . '-(\d{6})$/', $row['voucher_number'], $matches)) {
        $next = intval($matches[1]) + 1;
    }
    
    return $prefix . '-' . $year . '-' . str_pad($next, 6, '0', STR_PAD_LEFT);
}

// Update bank account balance
function update_bank_balance($mysqli, $bankAccountId, $amount, $isCredit = true) {
    if (!$bankAccountId) return false;
    
    $sql = $isCredit 
        ? "UPDATE bank_accounts SET current_balance = current_balance + ? WHERE id = ?"
        : "UPDATE bank_accounts SET current_balance = current_balance - ? WHERE id = ?";
    
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param('di', $amount, $bankAccountId);
    $result = $stmt->execute();
    $stmt->close();
    
    return $result;
}

// Amount to words converter (simplified for LKR and USD)
function amount_in_words($amount, $currency = 'LKR') {
    $amount = floatval($amount);
    $whole = floor($amount);
    $decimal = round(($amount - $whole) * 100);
    
    $ones = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine'];
    $teens = ['Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'];
    $tens = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'];
    $places = ['', 'Thousand', 'Million', 'Billion'];
    
    function convert_number($num) {
        global $ones, $teens, $tens;
        if ($num < 10) return $ones[$num];
        if ($num < 20) return $teens[$num - 10];
        if ($num < 100) return $tens[floor($num / 10)] . ($num % 10 ? ' ' . $ones[$num % 10] : '');
        return $ones[floor($num / 100)] . ' Hundred' . ($num % 100 ? ' and ' . convert_number($num % 100) : '');
    }
    
    function convert_whole($num) {
        global $places;
        if ($num == 0) return 'Zero';
        
        $parts = [];
        $place = 0;
        while ($num > 0) {
            $chunk = $num % 1000;
            if ($chunk > 0) {
                $part = convert_number($chunk);
                if ($places[$place]) {
                    $part .= ' ' . $places[$place];
                }
                array_unshift($parts, $part);
            }
            $num = floor($num / 1000);
            $place++;
        }
        return implode(', ', $parts);
    }
    
    $words = convert_whole($whole);
    if ($decimal > 0) {
        $words .= ' and ' . convert_number($decimal) . ' Cents';
    }
    
    $currencyNames = ['LKR' => 'Sri Lankan Rupees', 'USD' => 'US Dollars'];
    return $words . ' ' . ($currencyNames[$currency] ?? $currency);
}

// API Actions
switch ($action) {
    // ==================== BANK ACCOUNTS ====================
    
    case 'list_bank_accounts':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $isActive = isset($_GET['is_active']) ? intval($_GET['is_active']) : null;
        $currency = isset($_GET['currency']) ? trim($_GET['currency']) : null;
        
        $where = [];
        $params = [];
        $types = '';
        
        if ($isActive !== null) {
            $where[] = 'is_active = ?';
            $params[] = $isActive;
            $types .= 'i';
        }
        if ($currency) {
            $where[] = 'currency = ?';
            $params[] = $currency;
            $types .= 's';
        }
        
        $sql = "SELECT * FROM bank_accounts";
        if ($where) {
            $sql .= " WHERE " . implode(' AND ', $where);
        }
        $sql .= " ORDER BY is_default DESC, account_name ASC";
        
        if ($types) {
            $stmt = $mysqli->prepare($sql);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();
        } else {
            $result = $mysqli->query($sql);
        }
        
        $data = [];
        while ($row = $result->fetch_assoc()) {
            $data[] = $row;
        }
        
        json_response(['data' => $data]);
        break;
        
    case 'get_bank_account':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $id = intval($_GET['id'] ?? 0);
        if (!$id) {
            json_response(['message' => 'Bank account ID required'], 400);
        }
        
        $stmt = $mysqli->prepare("SELECT * FROM bank_accounts WHERE id = ?");
        $stmt->bind_param('i', $id);
        $stmt->execute();
        $result = $stmt->get_result();
        $data = $result->fetch_assoc();
        $stmt->close();
        
        if (!$data) {
            json_response(['message' => 'Bank account not found'], 404);
        }
        
        json_response(['data' => $data]);
        break;

    case 'delete_bank_account':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $id = intval($_POST['id'] ?? 0);
        if (!$id) {
            json_response(['message' => 'Bank account ID required'], 400);
        }
        
        // Check if there are transactions
        $check = $mysqli->query("SELECT COUNT(*) as cnt FROM transactions WHERE bank_account_id = $id");
        $row = $check->fetch_assoc();
        if ($row['cnt'] > 0) {
            json_response(['message' => 'Cannot delete: transactions exist for this account'], 400);
        }
        
        $stmt = $mysqli->prepare("DELETE FROM bank_accounts WHERE id = ?");
        $stmt->bind_param('i', $id);
        
        if ($stmt->execute()) {
            $stmt->close();
            json_response(['message' => 'Bank account deleted']);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to delete'], 500);
        }
        break;
        
    // ==================== TRANSACTIONS ====================
    
    case 'list_transactions':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $where = [];
        $params = [];
        $types = '';
        
        // Filters
        if (!empty($_GET['transaction_type'])) {
            $where[] = 't.transaction_type = ?';
            $params[] = $_GET['transaction_type'];
            $types .= 's';
        }
        if (!empty($_GET['account_head'])) {
            $where[] = 't.account_head = ?';
            $params[] = $_GET['account_head'];
            $types .= 's';
        }
        if (!empty($_GET['bank_account_id'])) {
            $where[] = 't.bank_account_id = ?';
            $params[] = intval($_GET['bank_account_id']);
            $types .= 'i';
        }
        if (!empty($_GET['party_name'])) {
            $where[] = 't.party_name LIKE ?';
            $params[] = '%' . $_GET['party_name'] . '%';
            $types .= 's';
        }
        if (!empty($_GET['date_from'])) {
            $where[] = 't.transaction_date >= ?';
            $params[] = $_GET['date_from'];
            $types .= 's';
        }
        if (!empty($_GET['date_to'])) {
            $where[] = 't.transaction_date <= ?';
            $params[] = $_GET['date_to'];
            $types .= 's';
        }
        if (isset($_GET['is_reconciled'])) {
            $where[] = 't.is_reconciled = ?';
            $params[] = intval($_GET['is_reconciled']);
            $types .= 'i';
        }
        if (!empty($_GET['approval_status'])) {
            $where[] = 't.approval_status = ?';
            $params[] = $_GET['approval_status'];
            $types .= 's';
        }
        if (!empty($_GET['voucher_number'])) {
            $where[] = 't.voucher_number LIKE ?';
            $params[] = '%' . $_GET['voucher_number'] . '%';
            $types .= 's';
        }
        
        // Non-admin users can only see their branch transactions
        if (!has_role(['admin', 'super_admin'])) {
            $branchId = $_SESSION['branch_id'] ?? 0;
            if ($branchId) {
                $where[] = 't.bank_account_id IN (SELECT id FROM bank_accounts WHERE FIND_IN_SET(?, branch_tags) OR ? = 0)';
                $params[] = $branchId;
                $params[] = $branchId;
                $types .= 'ii';
            }
        }
        
        $sql = "SELECT t.*, ba.account_name as bank_account_name, ba.account_number as bank_account_number
                FROM transactions t
                LEFT JOIN bank_accounts ba ON ba.id = t.bank_account_id";
        
        if ($where) {
            $sql .= " WHERE " . implode(' AND ', $where);
        }
        $sql .= " ORDER BY t.transaction_date DESC, t.id DESC";
        
        if ($types) {
            $stmt = $mysqli->prepare($sql);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();
        } else {
            $result = $mysqli->query($sql);
        }
        
        $data = [];
        while ($row = $result->fetch_assoc()) {
            $data[] = $row;
        }
        
        json_response(['data' => $data]);
        break;
        
    case 'get_transaction':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $id = intval($_GET['id'] ?? 0);
        if (!$id) {
            json_response(['message' => 'Transaction ID required'], 400);
        }
        
        $stmt = $mysqli->prepare("SELECT t.*, ba.account_name as bank_account_name, ba.currency
                                FROM transactions t
                                LEFT JOIN bank_accounts ba ON ba.id = t.bank_account_id
                                WHERE t.id = ?");
        $stmt->bind_param('i', $id);
        $stmt->execute();
        $result = $stmt->get_result();
        $data = $result->fetch_assoc();
        $stmt->close();
        
        if (!$data) {
            json_response(['message' => 'Transaction not found'], 404);
        }
        
        // Get attachments
        $attachments = [];
        $attResult = $mysqli->query("SELECT * FROM transaction_attachments WHERE transaction_id = $id");
        while ($att = $attResult->fetch_assoc()) {
            $attachments[] = $att;
        }
        $data['attachments'] = $attachments;
        
        json_response(['data' => $data]);
        break;
        
    case 'create_transaction':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $transactionType = $_POST['transaction_type'] ?? '';
        $transactionDate = $_POST['transaction_date'] ?? date('Y-m-d');
        $accountHead = trim($_POST['account_head'] ?? '');
        $bankAccountId = !empty($_POST['bank_account_id']) ? intval($_POST['bank_account_id']) : null;
        $partyName = trim($_POST['party_name'] ?? '');
        $amount = floatval($_POST['amount'] ?? 0);
        $modeOfPayment = $_POST['mode_of_payment'] ?? 'Cash';
        $narration = trim($_POST['narration'] ?? '');
        $documentReference = trim($_POST['document_reference'] ?? '');
        $costCenter = trim($_POST['cost_center'] ?? '');
        $taxAmount = floatval($_POST['tax_amount'] ?? 0);
        $taxPercent = floatval($_POST['tax_percent'] ?? 0);
        
        if (!$transactionType || !$accountHead || $amount <= 0) {
            json_response(['message' => 'Transaction type, account head, and valid amount are required'], 400);
        }
        
        // Generate voucher number
        $voucherNumber = generate_voucher_number($mysqli, $transactionType, $transactionDate);
        
        // Calculate amount in words
        $currency = 'LKR';
        if ($bankAccountId) {
            $baResult = $mysqli->query("SELECT currency FROM bank_accounts WHERE id = $bankAccountId");
            if ($ba = $baResult->fetch_assoc()) {
                $currency = $ba['currency'];
            }
        }
        $amountInWords = amount_in_words($amount, $currency);
        
        $enteredBy = $_SESSION['user_id'] ?? null;
        $approvalStatus = can_approve_transactions() ? 'Approved' : 'Pending';
        $isApproved = can_approve_transactions() ? 1 : 0;
        $approvedBy = can_approve_transactions() ? $enteredBy : null;
        $approvedAt = can_approve_transactions() ? date('Y-m-d H:i:s') : null;
        
        $stmt = $mysqli->prepare("INSERT INTO transactions
            (voucher_number, transaction_date, transaction_type, account_head, bank_account_id,
             party_name, amount, amount_in_words, mode_of_payment, narration, document_reference,
             cost_center, tax_amount, tax_percent, entered_by, approval_status, is_approved, approved_by, approved_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        
        $stmt->bind_param('ssssisssssssddsisss',
            $voucherNumber, $transactionDate, $transactionType, $accountHead, $bankAccountId,
            $partyName, $amount, $amountInWords, $modeOfPayment, $narration, $documentReference,
            $costCenter, $taxAmount, $taxPercent, $enteredBy, $approvalStatus, $isApproved, $approvedBy, $approvedAt
        );
        
        if ($stmt->execute()) {
            $transactionId = $stmt->insert_id;
            $stmt->close();
            
            // Update bank balance (Receipt = Credit, Payment = Debit)
            if ($bankAccountId) {
                $isCredit = ($transactionType === 'Receipt');
                update_bank_balance($mysqli, $bankAccountId, $amount, $isCredit);
            }
            
            json_response(['message' => 'Transaction created', 'id' => $transactionId, 'voucher_number' => $voucherNumber]);
        } else {
            $error = $stmt->error;
            $stmt->close();
            json_response(['message' => 'Failed to create: ' . $error], 500);
        }
        break;
        
    case 'approve_transaction':
        if (!can_approve_transactions()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $id = intval($_POST['id'] ?? 0);
        $status = $_POST['status'] ?? ''; // 'Approved' or 'Rejected'
        $reason = trim($_POST['reason'] ?? '');
        
        if (!$id || !in_array($status, ['Approved', 'Rejected'])) {
            json_response(['message' => 'Invalid request'], 400);
        }
        
        $approvedBy = $_SESSION['user_id'] ?? null;
        $approvedAt = date('Y-m-d H:i:s');
        
        $stmt = $mysqli->prepare("UPDATE transactions SET
            approval_status = ?, is_approved = ?, approved_by = ?, approved_at = ?, rejection_reason = ?
            WHERE id = ?");
        
        $isApproved = ($status === 'Approved') ? 1 : 0;
        $stmt->bind_param('siissi', $status, $isApproved, $approvedBy, $approvedAt, $reason, $id);
        
        if ($stmt->execute()) {
            $stmt->close();
            json_response(['message' => 'Transaction ' . strtolower($status)]);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to update'], 500);
        }
        break;
        
    case 'reconcile_transaction':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $id = intval($_POST['id'] ?? 0);
        $isReconciled = intval($_POST['is_reconciled'] ?? 1);
        
        if (!$id) {
            json_response(['message' => 'Transaction ID required'], 400);
        }
        
        $reconciledDate = $isReconciled ? date('Y-m-d') : null;
        $reconciledBy = $isReconciled ? ($_SESSION['user_id'] ?? null) : null;
        
        $stmt = $mysqli->prepare("UPDATE transactions SET
            is_reconciled = ?, reconciled_date = ?, reconciled_by = ?
            WHERE id = ?");
        $stmt->bind_param('isii', $isReconciled, $reconciledDate, $reconciledBy, $id);
        
        if ($stmt->execute()) {
            $stmt->close();
            json_response(['message' => 'Reconciliation status updated']);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to update'], 500);
        }
        break;
        
    case 'cancel_transaction':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $id = intval($_POST['id'] ?? 0);
        $reason = trim($_POST['reason'] ?? '');
        
        if (!$id) {
            json_response(['message' => 'Transaction ID required'], 400);
        }
        
        // Get transaction details for reversal
        $result = $mysqli->query("SELECT * FROM transactions WHERE id = $id");
        $transaction = $result->fetch_assoc();
        if (!$transaction) {
            json_response(['message' => 'Transaction not found'], 404);
        }
        if ($transaction['is_cancelled']) {
            json_response(['message' => 'Transaction already cancelled'], 400);
        }
        
        $cancelledBy = $_SESSION['user_id'] ?? null;
        $cancelledAt = date('Y-m-d H:i:s');
        
        $stmt = $mysqli->prepare("UPDATE transactions SET
            is_cancelled = 1, cancelled_by = ?, cancelled_at = ?, cancellation_reason = ?
            WHERE id = ?");
        $stmt->bind_param('issi', $cancelledBy, $cancelledAt, $reason, $id);
        
        if ($stmt->execute()) {
            $stmt->close();
            
            // Reverse bank balance
            if ($transaction['bank_account_id'] && $transaction['is_approved']) {
                $isCredit = ($transaction['transaction_type'] === 'Receipt');
                // Reverse the effect: if it was a credit, now debit and vice versa
                update_bank_balance($mysqli, $transaction['bank_account_id'], $transaction['amount'], !$isCredit);
            }
            
            json_response(['message' => 'Transaction cancelled']);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to cancel'], 500);
        }
        break;
        
    case 'generate_voucher':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $type = $_GET['type'] ?? 'Receipt';
        $date = $_GET['date'] ?? date('Y-m-d');
        
        $voucherNumber = generate_voucher_number($mysqli, $type, $date);
        json_response(['voucher_number' => $voucherNumber]);
        break;
        
    case 'get_finance_summary':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $dateFrom = $_GET['date_from'] ?? date('Y-m-01');
        $dateTo = $_GET['date_to'] ?? date('Y-m-d');
        
        // Bank account balances
        $bankQuery = "SELECT 
            COUNT(*) as total_accounts,
            SUM(CASE WHEN currency = 'LKR' THEN current_balance ELSE 0 END) as total_lkr_balance,
            SUM(CASE WHEN currency = 'USD' THEN current_balance ELSE 0 END) as total_usd_balance
            FROM bank_accounts WHERE is_active = 1";
        $bankResult = $mysqli->query($bankQuery);
        $bankSummary = $bankResult->fetch_assoc();
        
        // Transaction summary
        $txnQuery = "SELECT 
            COUNT(*) as total_transactions,
            SUM(CASE WHEN transaction_type = 'Receipt' AND is_approved = 1 AND is_cancelled = 0 THEN amount ELSE 0 END) as total_receipts,
            SUM(CASE WHEN transaction_type = 'Payment' AND is_approved = 1 AND is_cancelled = 0 THEN amount ELSE 0 END) as total_payments,
            SUM(CASE WHEN approval_status = 'Pending' THEN 1 ELSE 0 END) as pending_approvals,
            SUM(CASE WHEN is_reconciled = 0 AND is_approved = 1 AND is_cancelled = 0 THEN 1 ELSE 0 END) as unreconciled_count
            FROM transactions 
            WHERE transaction_date BETWEEN ? AND ?";
        
        $stmt = $mysqli->prepare($txnQuery);
        $stmt->bind_param('ss', $dateFrom, $dateTo);
        $stmt->execute();
        $txnResult = $stmt->get_result();
        $txnSummary = $txnResult->fetch_assoc();
        $stmt->close();
        
        json_response([
            'bank_summary' => $bankSummary,
            'transaction_summary' => $txnSummary,
            'period' => ['from' => $dateFrom, 'to' => $dateTo]
        ]);
        break;
        
    // ==================== BANK ACCOUNT CRUD ====================
    
    case 'create_bank_account':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $accountName = trim($_POST['account_name'] ?? '');
        $accountNumber = trim($_POST['account_number'] ?? '');
        $bankName = trim($_POST['bank_name'] ?? '');
        $branchName = trim($_POST['branch_name'] ?? '');
        $ifscCode = trim($_POST['ifsc_code'] ?? '');
        $swiftCode = trim($_POST['swift_code'] ?? '');
        $currency = trim($_POST['currency'] ?? 'LKR');
        $initialBalance = floatval($_POST['initial_balance'] ?? 0);
        $currentBalance = floatval($_POST['current_balance'] ?? $initialBalance);
        $accountType = trim($_POST['account_type'] ?? 'Current');
        $openingDate = trim($_POST['opening_date'] ?? null);
        $description = trim($_POST['description'] ?? '');
        $isDefault = intval($_POST['is_default'] ?? 0);
        $isActive = intval($_POST['is_active'] ?? 1);
        
        if (!$accountName || !$accountNumber || !$bankName) {
            json_response(['message' => 'Account name, account number, and bank name are required'], 400);
        }
        
        // If setting as default, clear other defaults
        if ($isDefault) {
            $mysqli->query("UPDATE bank_accounts SET is_default = 0 WHERE currency = '$currency'");
        }
        
        $stmt = $mysqli->prepare("INSERT INTO bank_accounts 
            (account_name, account_number, bank_name, branch_name, ifsc_code, swift_code,
             currency, initial_balance, current_balance, account_type, opening_date,
             description, is_default, is_active, created_by)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        
        $createdBy = $_SESSION['user_id'] ?? null;
        $stmt->bind_param('ssssssssssssiii',
            $accountName, $accountNumber, $bankName, $branchName, $ifscCode, $swiftCode,
            $currency, $initialBalance, $currentBalance, $accountType, $openingDate,
            $description, $isDefault, $isActive, $createdBy
        );
        
        if ($stmt->execute()) {
            $newId = $stmt->insert_id;
            $stmt->close();
            json_response(['success' => true, 'message' => 'Bank account created', 'id' => $newId]);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to create bank account: ' . $mysqli->error], 500);
        }
        break;
        
    case 'update_bank_account':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $accountId = intval($_POST['account_id'] ?? 0);
        if (!$accountId) {
            json_response(['message' => 'Account ID required'], 400);
        }
        
        $accountName = trim($_POST['account_name'] ?? '');
        $accountNumber = trim($_POST['account_number'] ?? '');
        $bankName = trim($_POST['bank_name'] ?? '');
        $branchName = trim($_POST['branch_name'] ?? '');
        $ifscCode = trim($_POST['ifsc_code'] ?? '');
        $swiftCode = trim($_POST['swift_code'] ?? '');
        $currency = trim($_POST['currency'] ?? 'LKR');
        $initialBalance = floatval($_POST['initial_balance'] ?? 0);
        $currentBalance = floatval($_POST['current_balance'] ?? 0);
        $accountType = trim($_POST['account_type'] ?? 'Current');
        $openingDate = trim($_POST['opening_date'] ?? null);
        $description = trim($_POST['description'] ?? '');
        $isDefault = intval($_POST['is_default'] ?? 0);
        $isActive = intval($_POST['is_active'] ?? 1);
        
        if (!$accountName || !$accountNumber || !$bankName) {
            json_response(['message' => 'Account name, account number, and bank name are required'], 400);
        }
        
        // If setting as default, clear other defaults
        if ($isDefault) {
            $mysqli->query("UPDATE bank_accounts SET is_default = 0 WHERE currency = '$currency' AND id != $accountId");
        }
        
        $stmt = $mysqli->prepare("UPDATE bank_accounts SET 
            account_name = ?, account_number = ?, bank_name = ?, branch_name = ?, 
            ifsc_code = ?, swift_code = ?, currency = ?, initial_balance = ?, 
            current_balance = ?, account_type = ?, opening_date = ?, description = ?, 
            is_default = ?, is_active = ?
            WHERE id = ?");
        
        $stmt->bind_param('ssssssssssssiii',
            $accountName, $accountNumber, $bankName, $branchName, $ifscCode, $swiftCode,
            $currency, $initialBalance, $currentBalance, $accountType, $openingDate,
            $description, $isDefault, $isActive, $accountId
        );
        
        if ($stmt->execute()) {
            $stmt->close();
            json_response(['success' => true, 'message' => 'Bank account updated']);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to update bank account'], 500);
        }
        break;
        
    case 'get_bank_account':
        if (!can_view_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        $accountId = intval($_GET['id'] ?? 0);
        if (!$accountId) {
            json_response(['message' => 'Account ID required'], 400);
        }
        
        $stmt = $mysqli->prepare("SELECT * FROM bank_accounts WHERE id = ?");
        $stmt->bind_param('i', $accountId);
        $stmt->execute();
        $result = $stmt->get_result();
        $account = $result->fetch_assoc();
        $stmt->close();
        
        if (!$account) {
            json_response(['message' => 'Bank account not found'], 404);
        }
        
        json_response(['success' => true, 'data' => $account]);
        break;
        
    case 'delete_bank_account':
        if (!can_edit_finance()) {
            json_response(['message' => 'Access denied'], 403);
        }
        
        verify_csrf();
        
        $accountId = intval($_POST['id'] ?? 0);
        if (!$accountId) {
            json_response(['message' => 'Account ID required'], 400);
        }
        
        // Check if account has transactions
        $checkStmt = $mysqli->prepare("SELECT COUNT(*) as count FROM transactions WHERE bank_account_id = ?");
        $checkStmt->bind_param('i', $accountId);
        $checkStmt->execute();
        $checkResult = $checkStmt->get_result();
        $hasTransactions = $checkResult->fetch_assoc()['count'] > 0;
        $checkStmt->close();
        
        if ($hasTransactions) {
            json_response(['message' => 'Cannot delete - account has linked transactions'], 400);
        }
        
        $stmt = $mysqli->prepare("DELETE FROM bank_accounts WHERE id = ?");
        $stmt->bind_param('i', $accountId);
        
        if ($stmt->execute()) {
            $stmt->close();
            json_response(['success' => true, 'message' => 'Bank account deleted']);
        } else {
            $stmt->close();
            json_response(['message' => 'Failed to delete bank account'], 500);
        }
        break;
        
    default:
        json_response(['message' => 'Unknown action'], 400);
}

// Helper function for JSON responses (if not defined)
if (!function_exists('json_response')) {
    function json_response($data, $httpCode = 200) {
        http_response_code($httpCode);
        header('Content-Type: application/json');
        echo json_encode($data);
        exit;
    }
}
?>
