<?php
declare(strict_types=1);

/**
 * File:
 * /home/jewellersbd/public_html/erp.jewellersbd.com/api/cash/cash_add.php
 *
 * Manual Cash IN / OUT entry
 * Called from: /cash_entry.php
 *
 * POST:
 * direction, category_id, cash_account_id, amount,
 * transaction_date, note, party_id
 */

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

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

function cash_add_response(
    bool $success,
    string $message,
    array $extra = [],
    int $statusCode = 200
): void {
    http_response_code($statusCode);

    echo json_encode(
        array_merge([
            'success' => $success,
            'message' => $message,
        ], $extra),
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );

    exit;
}

/**
 * General audit_log-এ safe entry।
 * Audit ব্যর্থ হলেও মূল cash entry বাতিল হবে না।
 */
function cash_add_safe_general_audit(
    PDO $pdo,
    int $transactionId,
    int $userId,
    string $note
): void {
    try {
        $stmt = $pdo->prepare(
            'INSERT INTO audit_log
                (
                    table_name,
                    record_id,
                    action,
                    changed_by,
                    changed_at,
                    ip_address,
                    note
                )
             VALUES
                (?, ?, ?, ?, NOW(), ?, ?)'
        );

        $stmt->execute([
            'cash_transactions',
            $transactionId,
            'INSERT',
            $userId,
            $_SERVER['REMOTE_ADDR'] ?? '',
            $note,
        ]);
    } catch (Throwable $e) {
        error_log(
            'cash_add.php general audit failed: ' . $e->getMessage()
        );
    }
}

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    cash_add_response(false, 'POST request প্রয়োজন।', [], 405);
}

require_login();

$userId = (int)($_SESSION['user_id'] ?? 0);

$postedDirection = strtoupper(
    trim((string)($_POST['direction'] ?? ''))
);

$categoryId = (int)($_POST['category_id'] ?? 0);
$accountId  = (int)($_POST['cash_account_id'] ?? 0);
$amount     = round((float)($_POST['amount'] ?? 0), 2);

$transactionDate = trim(
    (string)($_POST['transaction_date'] ?? date('Y-m-d'))
);

$note = trim((string)($_POST['note'] ?? ''));

$partyId = (int)($_POST['party_id'] ?? 0);
$partyId = $partyId > 0 ? $partyId : null;

/*
|--------------------------------------------------------------------------
| Basic validation
|--------------------------------------------------------------------------
*/

if (!in_array($postedDirection, ['IN', 'OUT'], true)) {
    cash_add_response(false, 'Cash IN অথবা OUT নির্বাচন করুন।', [], 422);
}

if ($categoryId <= 0) {
    cash_add_response(false, 'ক্যাটাগরি নির্বাচন করুন।', [], 422);
}

if ($accountId <= 0) {
    cash_add_response(false, 'অ্যাকাউন্ট নির্বাচন করুন।', [], 422);
}

if ($amount <= 0) {
    cash_add_response(false, 'টাকার পরিমাণ ০-এর বেশি দিন।', [], 422);
}

$dateObject = DateTime::createFromFormat('Y-m-d', $transactionDate);

if (
    !$dateObject
    || $dateObject->format('Y-m-d') !== $transactionDate
) {
    cash_add_response(false, 'সঠিক লেনদেনের তারিখ দিন।', [], 422);
}

if (!function_exists('gs_insert_cash_transaction')
    || !function_exists('gs_recalc_cash_account')) {
    cash_add_response(
        false,
        'Cash finance helper পাওয়া যায়নি।',
        [],
        500
    );
}

try {
    /*
    |--------------------------------------------------------------------------
    | Category যাচাই
    |--------------------------------------------------------------------------
    | Category-এর direction-ই হিসাবের আসল source of truth।
    */

    $categoryStmt = $pdo->prepare(
        'SELECT
            id,
            direction,
            category_name,
            category_name_bn
         FROM cash_categories
         WHERE id = ?
           AND is_active = 1
         LIMIT 1'
    );
    $categoryStmt->execute([$categoryId]);
    $category = $categoryStmt->fetch(PDO::FETCH_ASSOC);

    if (!$category) {
        cash_add_response(
            false,
            'সক্রিয় cash category পাওয়া যায়নি।',
            [],
            422
        );
    }

    $categoryDirection = strtoupper(
        (string)$category['direction']
    );

    if ($categoryDirection !== $postedDirection) {
        cash_add_response(
            false,
            'নির্বাচিত ক্যাটাগরি Cash '
                . $categoryDirection
                . '-এর জন্য।',
            [],
            422
        );
    }

    /*
    |--------------------------------------------------------------------------
    | Account যাচাই
    |--------------------------------------------------------------------------
    */

    $accountStmt = $pdo->prepare(
        'SELECT
            id,
            account_name,
            account_name_bn,
            current_balance
         FROM cash_accounts
         WHERE id = ?
           AND is_active = 1
           AND deleted_at IS NULL
         LIMIT 1'
    );
    $accountStmt->execute([$accountId]);
    $account = $accountStmt->fetch(PDO::FETCH_ASSOC);

    if (!$account) {
        cash_add_response(
            false,
            'সক্রিয় cash account পাওয়া যায়নি।',
            [],
            422
        );
    }

    /*
    |--------------------------------------------------------------------------
    | Cash entry save
    |--------------------------------------------------------------------------
    */

    $pdo->beginTransaction();

    $transactionId = 0;
    $lastInsertError = null;

    /*
     * একই মুহূর্তে দুইটি entry হলে voucher duplicate হতে পারে।
     * Unique voucher collision হলে সর্বোচ্চ ৩ বার চেষ্টা করবে।
     */
    for ($attempt = 1; $attempt <= 3; $attempt++) {
        try {
            $transactionId = gs_insert_cash_transaction($pdo, [
                'transaction_date' => $transactionDate,
                'cash_account_id'  => $accountId,
                'category_id'      => $categoryId,
                'amount'           => $amount,
                'note'             => $note,
                'reference_type'   => 'MANUAL',
                'party_id'         => $partyId,
                'created_by'       => $userId,
                'created_ip'       => $_SERVER['REMOTE_ADDR'] ?? '',
            ]);

            $lastInsertError = null;
            break;
        } catch (PDOException $e) {
            $lastInsertError = $e;

            $isDuplicate = ((string)$e->getCode() === '23000')
                && stripos($e->getMessage(), 'voucher') !== false;

            if (!$isDuplicate || $attempt === 3) {
                throw $e;
            }
        }
    }

    if ($transactionId <= 0) {
        if ($lastInsertError instanceof Throwable) {
            throw $lastInsertError;
        }

        throw new RuntimeException(
            'Cash transaction ID তৈরি হয়নি।'
        );
    }

    /*
     * current_balance সরাসরি যোগ-বিয়োগ নয়।
     * সম্পূর্ণ ledger থেকে আবার হিসাব করা হবে।
     */
    gs_recalc_cash_account($pdo, $accountId);

    $transactionStmt = $pdo->prepare(
        'SELECT
            voucher_no,
            direction,
            amount
         FROM cash_transactions
         WHERE id = ?
         LIMIT 1'
    );
    $transactionStmt->execute([$transactionId]);
    $transaction = $transactionStmt->fetch(PDO::FETCH_ASSOC);

    if (!$transaction) {
        throw new RuntimeException(
            'Saved cash transaction পাওয়া যায়নি।'
        );
    }

    $balanceStmt = $pdo->prepare(
        'SELECT current_balance
         FROM cash_accounts
         WHERE id = ?
         LIMIT 1'
    );
    $balanceStmt->execute([$accountId]);
    $newBalance = round(
        (float)$balanceStmt->fetchColumn(),
        2
    );

    $voucherNo = (string)($transaction['voucher_no'] ?? '');

    $categoryName = trim(
        (string)(
            $category['category_name_bn']
            ?: $category['category_name']
        )
    );

    $accountName = trim(
        (string)(
            $account['account_name_bn']
            ?: $account['account_name']
        )
    );

    cash_add_safe_general_audit(
        $pdo,
        $transactionId,
        $userId,
        'Manual cash entry saved'
            . ' | Voucher: ' . $voucherNo
            . ' | Direction: ' . $categoryDirection
            . ' | Amount: ' . number_format($amount, 2, '.', '')
            . ' | Account: ' . $accountName
            . ' | Category: ' . $categoryName
    );

    $pdo->commit();

    cash_add_response(true, 'সফলভাবে সেভ হয়েছে।', [
        'transaction_id' => $transactionId,
        'voucher_no'     => $voucherNo,
        'new_balance'    => $newBalance,
        'direction'      => $categoryDirection,
        'amount'         => $amount,
        'account_name'   => $accountName,
        'category_name'  => $categoryName,
    ]);

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

    error_log('cash_add.php failed: ' . $e->getMessage());

    cash_add_response(
        false,
        'Cash entry সংরক্ষণ করা যায়নি।',
        [],
        500
    );
}
