<?php
// Creates or updates an expense (an "id" field in the POST body means
// "edit that row"). Called by app.js via fetch (returns JSON) or, with
// JavaScript disabled, by a plain form POST (post/redirect/get back to the
// dashboard) — the progressive-enhancement fallback from Section 10.2.
// Edit-mode only ever arrives via fetch (the edit modal is JS-only), but
// the plain-POST fallback is still handled defensively below.

require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/validation.php';

require_login();

$isAjax = ($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest';

function respond_json(array $payload, int $status = 200): void
{
    http_response_code($status);
    header('Content-Type: application/json');
    echo json_encode($payload);
    exit;
}

function respond_redirect(array $errors, array $oldInput): void
{
    $_SESSION['expense_form_errors'] = $errors;
    $_SESSION['expense_form_old'] = $oldInput;
    header('Location: ../index.php');
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    if ($isAjax) {
        respond_json(['success' => false, 'error' => 'Invalid request.'], 405);
    }
    header('Location: ../index.php');
    exit;
}

if (!csrf_verify($_POST['csrf_token'] ?? null)) {
    if ($isAjax) {
        respond_json([
            'success' => false,
            'session_expired' => true,
            'error' => 'Your session expired — please log in again.',
        ], 400);
    }
    respond_redirect([], $_POST);
}

$db = get_db();
$id = (int) ($_POST['id'] ?? 0);
$isEdit = $id > 0;

if ($isEdit) {
    $existsStmt = $db->prepare('SELECT user_id FROM expenses WHERE id = :id');
    $existsStmt->execute(['id' => $id]);
    $ownerId = $existsStmt->fetchColumn();
    if ($ownerId === false) {
        $message = 'That entry no longer exists — it may have been deleted.';
        if ($isAjax) {
            respond_json(['success' => false, 'error' => $message], 404);
        }
        header('Location: ../index.php');
        exit;
    }
    // Sumona can edit her own expenses but not Motaher's — checked here,
    // not just hidden in the UI, since the browser is never trusted
    // (Section 10.2/14) for a state-changing request like this.
    if (!current_user_is_admin() && (int) $ownerId !== (int) current_user()['id']) {
        if ($isAjax) {
            respond_json(['success' => false, 'error' => 'You can only edit your own expenses.'], 403);
        }
        header('Location: ../index.php');
        exit;
    }
}

$result = validate_expense_input($_POST);

if (!empty($result['errors'])) {
    if ($isAjax) {
        respond_json(['success' => false, 'errors' => $result['errors']], 422);
    }
    respond_redirect($result['errors'], $_POST);
}

$data = $result['data'];

if ($isEdit) {
    $stmt = $db->prepare(
        'UPDATE expenses SET expense_date = :expense_date, amount = :amount, category_id = :category_id,
            payment_method_id = :payment_method_id, description = :description
         WHERE id = :id'
    );
    $stmt->execute([
        'expense_date'      => $data['expense_date'],
        'amount'            => $data['amount'],
        'category_id'       => $data['category_id'],
        'payment_method_id' => $data['payment_method_id'],
        'description'       => $data['description'],
        'id'                => $id,
    ]);
} else {
    $userId = (int) current_user()['id'];
    $stmt = $db->prepare(
        'INSERT INTO expenses (expense_date, amount, category_id, payment_method_id, user_id, description)
         VALUES (:expense_date, :amount, :category_id, :payment_method_id, :user_id, :description)'
    );
    $stmt->execute([
        'expense_date'      => $data['expense_date'],
        'amount'            => $data['amount'],
        'category_id'       => $data['category_id'],
        'payment_method_id' => $data['payment_method_id'],
        'user_id'           => $userId,
        'description'       => $data['description'],
    ]);
}

if (!$isAjax) {
    header('Location: ../index.php');
    exit;
}

$categoryStmt = $db->prepare('SELECT name FROM categories WHERE id = :id');
$categoryStmt->execute(['id' => $data['category_id']]);
$categoryName = $categoryStmt->fetchColumn();

// Refresh whichever month the dashboard currently has open — not
// necessarily today's month (Phase 5 month browsing).
$month = resolve_viewed_month($_POST['viewed_month'] ?? null);

respond_json([
    'success' => true,
    'action'  => $isEdit ? 'updated' : 'created',
    'toast'   => $categoryName . ' ' . format_money($data['amount']),
    'summary' => [
        'total_formatted' => format_money(get_month_expense_total($month)),
        'bdt_formatted'   => format_bdt_equivalent(get_month_expense_total($month)),
        'budget'          => get_budget_summary($month),
        'savings'         => get_month_savings($month),
    ],
    'categories' => build_category_chart_data(get_month_category_totals($month)),
    'recent'     => array_map('format_recent_expense_row', get_recent_expenses($month, 5)),
]);
