<?php
/**
 * expense_common.php
 * Shared bootstrap for the Expense Management module.
 * Include this at the top of every expense_*.php page BEFORE any output.
 */

if (session_status() === PHP_SESSION_NONE) session_start();
require_once __DIR__ . '/../config.php';

header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: SAMEORIGIN");
header("X-XSS-Protection: 1; mode=block");

if (!isset($conn)) { $conn = $db ?? $mysqli ?? null; }
if (!$conn) die('Database connection configuration not found.');

if (!function_exists('h')) {
    function h($s) { return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8'); }
}
if (!function_exists('set_flash')) {
    function set_flash($t, $m) { $_SESSION['flash'] = ['type' => $t, 'msg' => $m]; }
}
if (!function_exists('get_flash')) {
    function get_flash() {
        if (isset($_SESSION['flash'])) { $f = $_SESSION['flash']; unset($_SESSION['flash']); return $f; }
        return null;
    }
}

/** Require login; optionally restrict to a list of roles. Redirects otherwise. */
function expense_require_role(array $allowed_roles) {
    if (!isset($_SESSION['user_id']) || !isset($_SESSION['role'])) {
        header("Location: login.php");
        exit();
    }
    if (!in_array($_SESSION['role'], $allowed_roles, true)) {
        header("Location: login.php?denied=1");
        exit();
    }
}

/** Ensures a CSRF token exists in session and returns it. */
function expense_csrf_token() {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(16));
    }
    return $_SESSION['csrf_token'];
}

/** Validates the posted csrf field against the session token. */
function expense_csrf_valid() {
    return isset($_POST['csrf']) && isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $_POST['csrf']);
}

/**
 * Ensures the extra workflow columns/tables the expense module needs exist.
 * Safe to call on every request — each statement is a no-op if already applied.
 * (Kept here, instead of a manual migration step, so the module works the
 * moment these files are dropped onto an existing `expenses` table.)
 */
function expense_ensure_schema($conn) {
    static $done = false;
    if ($done) return;
    $done = true;

    $cols = [];
    $res = $conn->query("SHOW COLUMNS FROM expenses");
    if ($res) { while ($r = $res->fetch_assoc()) $cols[] = $r['Field']; }

    $alters = [];
    if (!in_array('reviewed_by', $cols, true))     $alters[] = "ADD COLUMN reviewed_by VARCHAR(11) DEFAULT NULL";
    if (!in_array('reviewed_by_name', $cols, true)) $alters[] = "ADD COLUMN reviewed_by_name VARCHAR(150) DEFAULT NULL";
    if (!in_array('reviewed_at', $cols, true))     $alters[] = "ADD COLUMN reviewed_at DATETIME DEFAULT NULL";
    if (!in_array('manager_remarks', $cols, true)) $alters[] = "ADD COLUMN manager_remarks VARCHAR(500) DEFAULT NULL";
    if (!in_array('rejection_reason', $cols, true))$alters[] = "ADD COLUMN rejection_reason VARCHAR(500) DEFAULT NULL";
    if (!in_array('updated_at', $cols, true))      $alters[] = "ADD COLUMN updated_at DATETIME DEFAULT NULL";
    if (!in_array('to_date', $cols, true))         $alters[] = "ADD COLUMN to_date DATE DEFAULT NULL";
    if (!in_array('claim_group', $cols, true))     $alters[] = "ADD COLUMN claim_group VARCHAR(40) DEFAULT NULL";

    if (!empty($alters)) {
        @$conn->query("ALTER TABLE expenses " . implode(', ', $alters));
    }

    @$conn->query("CREATE TABLE IF NOT EXISTS expense_categories (
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(100) NOT NULL,
        max_amount DECIMAL(10,2) DEFAULT NULL,
        active TINYINT(1) NOT NULL DEFAULT 1,
        created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $count = $conn->query("SELECT COUNT(*) c FROM expense_categories");
    if ($count && $count->fetch_assoc()['c'] == 0) {
        @$conn->query("INSERT INTO expense_categories (name, max_amount) VALUES
            ('Travel', NULL), ('Food', NULL), ('Accommodation', NULL),
            ('Office Supplies', NULL), ('Client Entertainment', NULL), ('Other', NULL)");
    }
}

/** Returns the manager-facing label + badge class for a status string. */
function expense_status_badge($status) {
    switch ($status) {
        case 'approved': return ['badge-completed', 'check', 'Approved'];
        case 'rejected': return ['badge-overdue', 'xmark', 'Rejected'];
        default:          return ['badge-pending', 'clock', 'Pending'];
    }
}