<?php
session_start();
header('Content-Type: application/json');

include '../layouts/dbconn.php';
include '../includes/accounting_posting.php';

if (!isset($_SESSION['user_id'])) {
    echo json_encode(['success' => false, 'message' => 'Unauthorized']);
    exit();
}

$allowed_roles = ['SUPER_ADMIN', 'HOSPITAL_ADMIN', 'ACCOUNTANT', 'FINANCE_MANAGER', 'BILLING_CLERK'];
if (!in_array($_SESSION['role_code'], $allowed_roles, true)) {
    echo json_encode(['success' => false, 'message' => 'Insufficient permissions']);
    exit();
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(['success' => false, 'message' => 'Invalid request method']);
    exit();
}

$supplier_id = (int)($_POST['supplier_id'] ?? 0);
$payable_account_id = (int)($_POST['payable_account_id'] ?? 0);
$bank_account_id = (int)($_POST['bank_account_id'] ?? 0);
$amount = round((float)($_POST['amount'] ?? 0), 2);
$entry_date = trim((string)($_POST['entry_date'] ?? date('Y-m-d')));
$description = trim((string)($_POST['description'] ?? 'AP reconciliation payment'));
$reference = trim((string)($_POST['reference'] ?? ''));

if ($supplier_id <= 0 || $payable_account_id <= 0 || $bank_account_id <= 0 || $amount <= 0) {
    echo json_encode(['success' => false, 'message' => 'Supplier, payable account, bank account and valid amount are required.']);
    exit();
}

$conn->begin_transaction();
try {
    accEnsureReconciliationAccounts($conn);

    $s = $conn->prepare("SELECT supplier_name, current_balance FROM suppliers WHERE supplier_id=? LIMIT 1");
    $s->bind_param('i', $supplier_id);
    $s->execute();
    $supplier = $s->get_result()->fetch_assoc();
    $s->close();
    if (!$supplier) throw new Exception('Supplier not found.');
    if ((float)$supplier['current_balance'] < $amount) throw new Exception('Payment exceeds supplier outstanding balance.');

    $p = $conn->prepare("SELECT account_id FROM chart_of_accounts WHERE account_id=? AND account_type='LIABILITY' AND is_active=1 LIMIT 1");
    $p->bind_param('i', $payable_account_id);
    $p->execute();
    $payableOk = $p->get_result()->fetch_assoc();
    $p->close();
    if (!$payableOk) throw new Exception('Payable account must be an active liability account.');

    $b = $conn->prepare("SELECT account_id FROM chart_of_accounts WHERE account_id=? AND account_type='ASSET' AND is_active=1 LIMIT 1");
    $b->bind_param('i', $bank_account_id);
    $b->execute();
    $bankOk = $b->get_result()->fetch_assoc();
    $b->close();
    if (!$bankOk) throw new Exception('Bank/Cash/MPESA account must be an active asset account.');

    $lineSeed = [
        ['account_id' => $payable_account_id],
        ['account_id' => $bank_account_id],
    ];
    $desc = '[PAYMENT] ' . $description . ($reference !== '' ? ' (Ref: '.$reference.')' : '');
    $prefix = accClassifyPostingPrefix($conn, $lineSeed, $desc);
    $journal_number = accGenerateJournalNumberByPrefix($conn, $prefix);
    $fiscal_year = (int)date('Y', strtotime($entry_date));
    $fiscal_period = (int)date('n', strtotime($entry_date));
    $created_by = (int)$_SESSION['user_id'];
    $notes = 'AP bank reconciliation allocation';

    $je = $conn->prepare("INSERT INTO journal_entries
        (journal_number, entry_date, entry_type, reference_type, reference_id, description, total_debit, total_credit, status, fiscal_year, fiscal_period, notes, created_by)
        VALUES (?, ?, 'MANUAL', 'GENERAL', ?, ?, ?, ?, 'POSTED', ?, ?, ?, ?)");
    $je->bind_param('ssisddiisi', $journal_number, $entry_date, $supplier_id, $desc, $amount, $amount, $fiscal_year, $fiscal_period, $notes, $created_by);
    if (!$je->execute()) throw new Exception($je->error);
    $journal_id = (int)$conn->insert_id;
    $je->close();

    $jl = $conn->prepare("INSERT INTO journal_entry_lines (journal_id, line_number, account_id, debit_amount, credit_amount, description)
                          VALUES (?, ?, ?, ?, ?, ?)");
    $zero = 0.0;
    $line1 = 1;
    $line2 = 2;
    $jl->bind_param('iiidds', $journal_id, $line1, $payable_account_id, $amount, $zero, $desc);
    if (!$jl->execute()) throw new Exception($jl->error);
    $jl->bind_param('iiidds', $journal_id, $line2, $bank_account_id, $zero, $amount, $desc);
    if (!$jl->execute()) throw new Exception($jl->error);
    $jl->close();

    $post = $conn->prepare("CALL PostJournalToLedger(?)");
    $post->bind_param('i', $journal_id);
    if (!$post->execute()) throw new Exception('Failed to post journal to ledger: '.$post->error);
    $post->close();
    while ($conn->more_results()) {
        $conn->next_result();
        if ($res = $conn->store_result()) $res->free();
    }

    $su = $conn->prepare("UPDATE suppliers SET current_balance=current_balance-? WHERE supplier_id=?");
    $su->bind_param('di', $amount, $supplier_id);
    if (!$su->execute()) throw new Exception($su->error);
    $su->close();

    $conn->query("CREATE TABLE IF NOT EXISTS ap_reconciliation_matches (
        match_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        supplier_id INT NOT NULL,
        journal_id INT NOT NULL,
        payable_account_id INT NOT NULL,
        bank_account_id INT NOT NULL,
        amount DECIMAL(15,2) NOT NULL,
        reference VARCHAR(100) NULL,
        created_by INT NOT NULL,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    $rm = $conn->prepare("INSERT INTO ap_reconciliation_matches
        (supplier_id, journal_id, payable_account_id, bank_account_id, amount, reference, created_by)
        VALUES (?, ?, ?, ?, ?, ?, ?)");
    $rm->bind_param('iiiidsi', $supplier_id, $journal_id, $payable_account_id, $bank_account_id, $amount, $reference, $created_by);
    $rm->execute();
    $rm->close();

    $conn->commit();
    echo json_encode([
        'success' => true,
        'message' => 'AP payment allocated to supplier successfully.',
        'journal_number' => $journal_number,
        'posting_prefix' => $prefix
    ]);
} catch (Exception $e) {
    $conn->rollback();
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
exit();
