<?php
/**
 * api/pawn/pledge_close.php
 * POST: pledge_id, close_date, final_interest, final_principal,
 *       discount, discount_reason, payments(JSON array), close_note
 *
 * Business Logic:
 *   - final_interest = লকার ভাড়া হিসাব
 *   - discount সবসময় লকার ভাড়া থেকে বাদ যাবে
 *   - মূল টাকা কখনো proportional discount হবে না
 *
 * Example:
 *   লকার ভাড়া 43,633.33
 *   ছাড় 633.33
 *   নেট লকার ভাড়া 43,000.00
 *   মূল 25,000.00
 *   মোট 68,000.00
 *
 * Audit:
 *   pawn_payments INSERT
 *   cash_transactions INSERT
 *   pawn_pledges UPDATE
 */

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

header('Content-Type: application/json; charset=utf-8');

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

$user_id = (int)($_SESSION['user_id'] ?? 1);
$ip      = $_SERVER['REMOTE_ADDR'] ?? '';

function pc_send($success, $message, $extra = [], $code = 200)
{
    http_response_code($code);
    echo json_encode(array_merge([
        'success' => $success,
        'message' => $message
    ], $extra), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

/**
 * Safe Audit Logger
 */
function pledge_close_safe_audit_log($pdo, $tableName, $recordId, $action, $changedBy, $note = '')
{
    try {
        if (!$pdo || !($pdo instanceof PDO)) {
            return;
        }

        $ipAddress = $_SERVER['REMOTE_ADDR'] ?? '';

        $stmt = $pdo->prepare("
            INSERT INTO audit_log
                (table_name, record_id, action, changed_by, changed_at, ip_address, note)
            VALUES
                (:table_name, :record_id, :action, :changed_by, NOW(), :ip_address, :note)
        ");

        $stmt->execute([
            ':table_name' => $tableName,
            ':record_id'  => (int)$recordId,
            ':action'     => $action,
            ':changed_by' => (int)$changedBy,
            ':ip_address' => $ipAddress,
            ':note'       => $note
        ]);

    } catch (Throwable $e) {
        return;
    }
}

$pledge_id       = (int)($_POST['pledge_id'] ?? 0);
$close_date      = $_POST['close_date'] ?? date('Y-m-d');
$locker_rent_calc = round((float)($_POST['final_interest'] ?? 0), 2);  // UI old field: final_interest
$final_principal = round((float)($_POST['final_principal'] ?? 0), 2);
$discount        = round((float)($_POST['discount'] ?? 0), 2);
$disc_reason     = trim((string)($_POST['discount_reason'] ?? ''));
$close_note      = trim((string)($_POST['close_note'] ?? ''));
$payments_raw    = $_POST['payments'] ?? '[]';
$payments        = json_decode($payments_raw, true);

if (!is_array($payments)) {
    $payments = [];
}

if ($pledge_id <= 0) {
    pc_send(false, 'pledge_id দেওয়া হয়নি।', [], 422);
}

if ($locker_rent_calc < 0 || $final_principal < 0 || $discount < 0) {
    pc_send(false, 'লকার ভাড়া, মূল টাকা বা ছাড় negative হতে পারে না।', [], 422);
}

/**
 * Load pledge
 */
$s = $pdo->prepare("
    SELECT 
        p.*, 
        pa.name AS party_name 
    FROM pawn_pledges p 
    LEFT JOIN parties pa ON pa.id = p.party_id 
    WHERE p.id = ? 
    LIMIT 1
");
$s->execute([$pledge_id]);
$pledge = $s->fetch(PDO::FETCH_ASSOC);

if (!$pledge) {
    pc_send(false, 'বন্ধক পাওয়া যায়নি।', [], 404);
}

if (($pledge['status'] ?? '') === 'CLOSED') {
    pc_send(false, 'এই বন্ধক আগেই বন্ধ হয়ে গেছে।', [], 422);
}

$outstanding = round((float)($pledge['outstanding_principal'] ?? 0), 2);

if ($final_principal > $outstanding + 0.01) {
    pc_send(false, 'মূল টাকা বকেয়ার বেশি হতে পারে না।', [], 422);
}

/**
 * Business rule:
 * ছাড় শুধুমাত্র লকার ভাড়া থেকে বাদ যাবে।
 * ছাড় যদি লকার ভাড়ার বেশি হয়, সেটা allowed না।
 */
if ($discount > $locker_rent_calc + 0.01) {
    pc_send(false, 'ছাড় লকার ভাড়ার বেশি হতে পারে না।', [
        'locker_rent_calc' => $locker_rent_calc,
        'discount' => $discount
    ], 422);
}

$net_locker_rent = round(max(0, $locker_rent_calc - $discount), 2);
$net_total       = round($net_locker_rent + $final_principal, 2);
$gross_total     = round($locker_rent_calc + $final_principal, 2);

$pay_total = 0;
foreach ($payments as $p) {
    $pay_total += round((float)($p['amount'] ?? 0), 2);
}

if ($net_total > 0 && empty($payments)) {
    pc_send(false, 'কমপক্ষে একটি cash account-এ পরিমাণ দিন।', [], 422);
}

if ($net_total > 0 && !empty($payments) && abs($pay_total - $net_total) > 1) {
    pc_send(false, 'Payment মোট মিলছে না।', [
        'net_total' => $net_total,
        'pay_total' => $pay_total
    ], 422);
}

/**
 * Voucher helper
 */
function makeVoucher(PDO $pdo): string
{
    $p = 'CV-' . date('Ym') . '-';

    $stmt = $pdo->prepare("
        SELECT COUNT(*) 
        FROM cash_transactions 
        WHERE voucher_no LIKE ?
    ");
    $stmt->execute([$p . '%']);

    $c = (int)$stmt->fetchColumn();

    return $p . str_pad($c + 1, 4, '0', STR_PAD_LEFT);
}

try {
    $pdo->beginTransaction();

    /**
     * 1. pawn_payments record
     *
     * DB column interest_paid পুরনো নাম।
     * এখানে net_locker_rent রাখা হচ্ছে, যাতে payment history বাস্তব collected amount দেখায়।
     */
    $pawn_payment_id = null;

    if ($net_total > 0 || $gross_total > 0) {
        $note_txt = 'বন্ধক বন্ধ';

        if ($locker_rent_calc > 0) {
            $note_txt .= ' | লকার ভাড়া হিসাব: ৳' . number_format($locker_rent_calc, 2);
        }

        if ($discount > 0) {
            $note_txt .= ' | লকার ভাড়া ছাড়: ৳' . number_format($discount, 2);
            if ($disc_reason !== '') {
                $note_txt .= ' (' . $disc_reason . ')';
            }
        }

        if ($net_locker_rent > 0) {
            $note_txt .= ' | নেট লকার ভাড়া: ৳' . number_format($net_locker_rent, 2);
        }

        if ($final_principal > 0) {
            $note_txt .= ' | মূল টাকা: ৳' . number_format($final_principal, 2);
        }

        if ($close_note !== '') {
            $note_txt .= ' | ' . $close_note;
        }

        $first_acc = !empty($payments) ? (int)($payments[0]['cash_account_id'] ?? 0) : 0;

        $ins = $pdo->prepare("
            INSERT INTO pawn_payments
                (
                    pledge_id,
                    payment_date,
                    amount,
                    interest_paid,
                    principal_paid,
                    cash_account_id,
                    note,
                    created_at
                )
            VALUES
                (?, ?, ?, ?, ?, ?, ?, NOW())
        ");

        $ins->execute([
            $pledge_id,
            $close_date,
            $net_total,
            $net_locker_rent,
            $final_principal,
            $first_acc,
            $note_txt
        ]);

        $pawn_payment_id = (int)$pdo->lastInsertId();

        pledge_close_safe_audit_log(
            $pdo,
            'pawn_payments',
            $pawn_payment_id,
            'INSERT',
            $user_id,
            "Pledge close payment recorded"
            . " | Pledge: " . ($pledge['pledge_code'] ?? '')
            . " | Locker Rent Calc: " . number_format($locker_rent_calc, 2)
            . " | Locker Rent Discount: " . number_format($discount, 2)
            . " | Net Locker Rent: " . number_format($net_locker_rent, 2)
            . " | Principal: " . number_format($final_principal, 2)
            . " | Net Collected: " . number_format($net_total, 2)
        );
    }

    /**
     * 2. Cash transactions
     *
     * New allocation:
     *   - আগে নেট লকার ভাড়া portion যাবে
     *   - তারপর মূল টাকা portion যাবে
     *   - কোনো proportional discount নেই
     */
    $cashTxnIds = [];

    $remainingRent = $net_locker_rent;
    $remainingPrin = $final_principal;

    foreach ($payments as $pay) {
        $acc_id = (int)($pay['cash_account_id'] ?? 0);
        $amt    = round((float)($pay['amount'] ?? 0), 2);

        if ($acc_id <= 0 || $amt <= 0) {
            continue;
        }

        $caStmt = $pdo->prepare("
            SELECT id, account_name 
            FROM cash_accounts 
            WHERE id = ? AND is_active = 1 
            LIMIT 1
        ");
        $caStmt->execute([$acc_id]);
        $acc = $caStmt->fetch(PDO::FETCH_ASSOC);

        if (!$acc) {
            throw new Exception('Cash account পাওয়া যায়নি বা inactive: #' . $acc_id);
        }

        /**
         * This account amount থেকে প্রথমে rent fill হবে,
         * তারপর principal fill হবে।
         */
        $rent_part = round(min($amt, $remainingRent), 2);
        $left_amt  = round($amt - $rent_part, 2);
        $prin_part = round(min($left_amt, $remainingPrin), 2);

        $remainingRent = round($remainingRent - $rent_part, 2);
        $remainingPrin = round($remainingPrin - $prin_part, 2);

        /**
         * লকার ভাড়া IN, category_id=4
         */
        if ($rent_part > 0) {
            $v = makeVoucher($pdo);

            $n = 'লকার ভাড়া আদায় (ক্লোজিং) | '
                . ($pledge['pledge_code'] ?? '')
                . ' | ' . ($pledge['party_name'] ?? '');

            if ($discount > 0) {
                $n .= ' | ছাড়: ৳' . number_format($discount, 2);
            }

            $stmtRent = $pdo->prepare("
                INSERT INTO cash_transactions
                    (
                        voucher_no,
                        transaction_date,
                        cash_account_id,
                        category_id,
                        direction,
                        amount,
                        note,
                        reference_type,
                        reference_id,
                        party_id,
                        pledge_id,
                        created_by,
                        created_ip,
                        created_at
                    )
                VALUES
                    (?, ?, ?, 4, 'IN', ?, ?, 'PLEDGE', ?, ?, ?, ?, ?, NOW())
            ");

            $stmtRent->execute([
                $v,
                $close_date,
                $acc_id,
                $rent_part,
                $n,
                $pawn_payment_id,
                $pledge['party_id'],
                $pledge_id,
                $user_id,
                $ip
            ]);

            $rentTxnId = (int)$pdo->lastInsertId();
            $cashTxnIds[] = $rentTxnId;

            $pdo->prepare("
                UPDATE cash_accounts 
                SET current_balance = current_balance + ? 
                WHERE id = ?
            ")->execute([
                $rent_part,
                $acc_id
            ]);

            pledge_close_safe_audit_log(
                $pdo,
                'cash_transactions',
                $rentTxnId,
                'INSERT',
                $user_id,
                "Locker rent cash received at pledge closing"
                . " | Pledge: " . ($pledge['pledge_code'] ?? '')
                . " | Voucher: " . $v
                . " | Account: " . ($acc['account_name'] ?? '') . " (#" . $acc_id . ")"
                . " | Amount: " . number_format($rent_part, 2)
                . " | Discount Applied From Locker Rent: " . number_format($discount, 2)
            );
        }

        /**
         * মূল টাকা IN, category_id=5
         */
        if ($prin_part > 0) {
            $v = makeVoucher($pdo);

            $n = 'মূল টাকা ফেরত (ক্লোজিং) | '
                . ($pledge['pledge_code'] ?? '')
                . ' | ' . ($pledge['party_name'] ?? '');

            $stmtPrincipal = $pdo->prepare("
                INSERT INTO cash_transactions
                    (
                        voucher_no,
                        transaction_date,
                        cash_account_id,
                        category_id,
                        direction,
                        amount,
                        note,
                        reference_type,
                        reference_id,
                        party_id,
                        pledge_id,
                        created_by,
                        created_ip,
                        created_at
                    )
                VALUES
                    (?, ?, ?, 5, 'IN', ?, ?, 'PLEDGE', ?, ?, ?, ?, ?, NOW())
            ");

            $stmtPrincipal->execute([
                $v,
                $close_date,
                $acc_id,
                $prin_part,
                $n,
                $pawn_payment_id,
                $pledge['party_id'],
                $pledge_id,
                $user_id,
                $ip
            ]);

            $principalTxnId = (int)$pdo->lastInsertId();
            $cashTxnIds[] = $principalTxnId;

            $pdo->prepare("
                UPDATE cash_accounts 
                SET current_balance = current_balance + ? 
                WHERE id = ?
            ")->execute([
                $prin_part,
                $acc_id
            ]);

            pledge_close_safe_audit_log(
                $pdo,
                'cash_transactions',
                $principalTxnId,
                'INSERT',
                $user_id,
                "Principal cash received at pledge closing"
                . " | Pledge: " . ($pledge['pledge_code'] ?? '')
                . " | Voucher: " . $v
                . " | Account: " . ($acc['account_name'] ?? '') . " (#" . $acc_id . ")"
                . " | Amount: " . number_format($prin_part, 2)
            );
        }
    }

    if (abs($remainingRent) > 1 || abs($remainingPrin) > 1) {
        throw new Exception(
            'Allocation mismatch. Remaining Locker Rent: '
            . number_format($remainingRent, 2)
            . ', Remaining Principal: '
            . number_format($remainingPrin, 2)
        );
    }

    /**
     * 3. Pledge CLOSED
     */
    $close_full = 'বন্ধক বন্ধ করা হয়েছে।';

    if ($locker_rent_calc > 0) {
        $close_full .= ' লকার ভাড়া হিসাব: ৳' . number_format($locker_rent_calc, 2) . '.';
    }

    if ($discount > 0) {
        $close_full .= ' লকার ভাড়া ছাড়: ৳' . number_format($discount, 2);
        if ($disc_reason !== '') {
            $close_full .= ' (' . $disc_reason . ')';
        }
        $close_full .= '.';
    }

    if ($net_locker_rent > 0) {
        $close_full .= ' নেট লকার ভাড়া: ৳' . number_format($net_locker_rent, 2) . '.';
    }

    if ($final_principal > 0) {
        $close_full .= ' মূল টাকা: ৳' . number_format($final_principal, 2) . '.';
    }

    if ($close_note !== '') {
        $close_full .= ' ' . $close_note;
    }

    $upd = $pdo->prepare("
        UPDATE pawn_pledges
        SET 
            status = 'CLOSED',
            outstanding_principal = 0,
            closed_at = NOW(),
            note = CONCAT(IFNULL(note, ''), ' | CLOSED: ', ?)
        WHERE id = ?
    ");

    $upd->execute([
        $close_full,
        $pledge_id
    ]);

    pledge_close_safe_audit_log(
        $pdo,
        'pawn_pledges',
        $pledge_id,
        'UPDATE',
        $user_id,
        "Pledge closed and item returned"
        . " | Pledge: " . ($pledge['pledge_code'] ?? '')
        . " | Old Outstanding: " . number_format($outstanding, 2)
        . " | Locker Rent Calc: " . number_format($locker_rent_calc, 2)
        . " | Locker Rent Discount: " . number_format($discount, 2)
        . " | Net Locker Rent: " . number_format($net_locker_rent, 2)
        . " | Principal: " . number_format($final_principal, 2)
        . " | Net Collected: " . number_format($net_total, 2)
    );

    $pdo->commit();

    echo json_encode([
        'success'             => true,
        'message'             => 'বন্ধক সফলভাবে বন্ধ হয়েছে। গহনা ফেরত দিন।',
        'pledge_code'         => $pledge['pledge_code'],
        'locker_rent_calc'    => $locker_rent_calc,
        'discount'            => $discount,
        'net_locker_rent'     => $net_locker_rent,
        'principal_collected' => $final_principal,
        'gross_total'         => $gross_total,
        'net_collected'       => $net_total,
        'accounts_used'       => count($payments),
        'pawn_payment_id'     => $pawn_payment_id,
        'cash_txn_ids'        => $cashTxnIds
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

} catch (Throwable $e) {
    if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
        $pdo->rollBack();
    }

    echo json_encode([
        'success' => false,
        'message' => 'DB error: ' . $e->getMessage()
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}