<?php
require_once __DIR__ . '/../config/database.php';

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

function e(?string $value): string
{
    return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}

function redirect(string $url): void
{
    header('Location: ' . $url);
    exit;
}

function app_name(): string
{
    return app_config()['app_name'];
}

function flash_set(string $key, string $message): void
{
    $_SESSION['flash'][$key] = $message;
}

function flash_get(string $key): ?string
{
    if (!isset($_SESSION['flash'][$key])) {
        return null;
    }
    $message = $_SESSION['flash'][$key];
    unset($_SESSION['flash'][$key]);
    return $message;
}

function csrf_token(): string
{
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function validate_csrf(): void
{
    $token = $_POST['csrf_token'] ?? '';
    if (!$token || !hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
        http_response_code(422);
        exit('Invalid CSRF token.');
    }
}

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

function report_categories(): array
{
    return ['Biscuits', 'Gem', 'Cracker', 'Chocolate', 'Snacks', 'Wafer'];
}

function visit_types(): array
{
    return ['Review', 'Audit', 'Training'];
}

function issue_types(): array
{
    return ['Sales', 'Stock', 'Distribution', 'Team Discipline'];
}

function severity_levels(): array
{
    return ['N/A', 'Low', 'Medium', 'High'];
}

function follow_up_periods(): array
{
    return ['1 month', '3 months', '6 months'];
}

function yes_no_options(): array
{
    return ['Yes', 'No'];
}

function ensure_upload_dir(): string
{
    $dir = app_config()['upload_dir'];
    if (!is_dir($dir)) {
        mkdir($dir, 0777, true);
    }
    return $dir;
}

function save_uploaded_file(array $file, string $prefix = 'file'): ?string
{
    if (empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
        return null;
    }

    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)) ?: 'jpg';
    $allowed = ['jpg', 'jpeg', 'png', 'webp'];
    if (!in_array($ext, $allowed, true)) {
        $ext = 'jpg';
    }

    $name = $prefix . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
    $target = ensure_upload_dir() . '/' . $name;
    move_uploaded_file($file['tmp_name'], $target);
    return 'uploads/' . $name;
}

function save_base64_image(?string $dataUri, string $prefix = 'capture'): ?string
{
    if (!$dataUri || strpos($dataUri, 'base64,') === false) {
        return null;
    }

    [$meta, $content] = explode('base64,', $dataUri, 2);
    $binary = base64_decode($content, true);
    if ($binary === false) {
        return null;
    }

    $ext = str_contains($meta, 'image/jpeg') ? 'jpg' : (str_contains($meta, 'image/webp') ? 'webp' : 'png');
    $name = $prefix . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
    $target = ensure_upload_dir() . '/' . $name;
    file_put_contents($target, $binary);
    return 'uploads/' . $name;
}

function current_datetime_local(): string
{
    return date('Y-m-d\TH:i');
}

function current_user(): ?array
{
    return $_SESSION['user'] ?? null;
}

function get_accessible_agents(PDO $pdo, array $user): array
{
    return array_column(get_accessible_agent_records($pdo, $user), 'agent_name');
}

function get_accessible_agent_records(PDO $pdo, array $user): array
{
    if (($user['role'] ?? '') === 'admin') {
        $stmt = $pdo->query(
            "SELECT agent_name, rsm_name, region, sub_region, territory_name, dbaddres, dbcontact, stores_name
             FROM agentsmrd
             WHERE agent_name IS NOT NULL AND agent_name <> ''
             GROUP BY agent_name, rsm_name, region, sub_region, territory_name, dbaddres, dbcontact, stores_name
             ORDER BY agent_name"
        );
        return $stmt->fetchAll();
    }

    $stmt = $pdo->prepare(
        "SELECT a.agent_name, a.rsm_name, a.region, a.sub_region, a.territory_name, a.dbaddres, a.dbcontact, a.stores_name
         FROM agentsmrd a
         LEFT JOIN user_agent_assignments uaa
           ON uaa.agent_name = a.agent_name AND uaa.user_id = :uid
         WHERE a.agent_name IS NOT NULL
           AND a.agent_name <> ''
           AND (uaa.user_id IS NOT NULL OR a.rsm_name = :full_name)
         GROUP BY a.agent_name, a.rsm_name, a.region, a.sub_region, a.territory_name, a.dbaddres, a.dbcontact, a.stores_name
         ORDER BY a.agent_name"
    );
    $stmt->execute([
        ':uid' => $user['id'],
        ':full_name' => $user['full_name'],
    ]);
    return $stmt->fetchAll();
}

function can_access_agent(PDO $pdo, array $user, string $agentName): bool
{
    return in_array($agentName, get_accessible_agents($pdo, $user), true);
}

function can_access_report(PDO $pdo, array $user, int $reportId): bool
{
    if (($user['role'] ?? '') === 'admin') {
        return true;
    }
    $stmt = $pdo->prepare(
        "SELECT COUNT(*)
         FROM visit_reports vr
         WHERE vr.id = :id
           AND vr.agent_name IN (
               SELECT agent_name FROM user_agent_assignments WHERE user_id = :uid
               UNION
               SELECT agent_name FROM agentsmrd WHERE rsm_name = :full_name
           )"
    );
    $stmt->execute([
        ':id' => $reportId,
        ':uid' => $user['id'],
        ':full_name' => $user['full_name'],
    ]);
    return (int) $stmt->fetchColumn() > 0;
}

function require_report_access(PDO $pdo, array $user, int $reportId): void
{
    if (!can_access_report($pdo, $user, $reportId)) {
        http_response_code(403);
        exit('You do not have permission to access this report.');
    }
}

function upsert_progress(PDO $pdo, int $reportId, int $formNo): void
{
    $stmt = $pdo->prepare(
        "INSERT INTO visit_form_progress (report_id, form_no, is_saved, saved_at)
         VALUES (:report_id, :form_no, 1, NOW())
         ON DUPLICATE KEY UPDATE is_saved = 1, saved_at = NOW()"
    );
    $stmt->execute([
        ':report_id' => $reportId,
        ':form_no' => $formNo,
    ]);
}

function get_saved_form_numbers(PDO $pdo, int $reportId): array
{
    $stmt = $pdo->prepare('SELECT form_no FROM visit_form_progress WHERE report_id = ? AND is_saved = 1');
    $stmt->execute([$reportId]);
    return array_map('intval', array_column($stmt->fetchAll(), 'form_no'));
}

function missing_required_forms(PDO $pdo, int $reportId, array $requiredForms): array
{
    $saved = get_saved_form_numbers($pdo, $reportId);
    return array_values(array_diff($requiredForms, $saved));
}

function compute_sales_status(float $target, float $achievement): string
{
    if ($target <= 0 && $achievement <= 0) {
        return 'No activity';
    }
    if ($target > 0 && $achievement >= $target) {
        return 'Achieved / On track';
    }
    if ($target > 0 && $achievement >= ($target * 0.75)) {
        return 'Moderate gap';
    }
    return 'Needs attention';
}

function fetch_report_bundle(PDO $pdo, int $reportId): array
{
    $bundle = [];
    $stmt = $pdo->prepare('SELECT * FROM visit_reports WHERE id = ?');
    $stmt->execute([$reportId]);
    $bundle['report'] = $stmt->fetch();

    $singleTables = [
        'db_profile' => 'report_db_profile',
        'general' => 'report_general_remarks',
    ];
    foreach ($singleTables as $key => $table) {
        $stmt = $pdo->prepare("SELECT * FROM {$table} WHERE report_id = ?");
        $stmt->execute([$reportId]);
        $bundle[$key] = $stmt->fetch() ?: [];
    }

    $multiTables = [
        'sales_snapshot' => 'report_sales_snapshot',
        'stock_status' => 'report_stock_status',
        'issues' => 'report_issues',
        'actions_db' => 'report_actions_db',
        'actions_staff' => 'report_actions_staff',
        'follow_ups' => 'report_follow_ups',
        'progress' => 'visit_form_progress',
    ];
    foreach ($multiTables as $key => $table) {
        $orderBy = $table === 'visit_form_progress' ? 'form_no ASC' : 'id ASC';
        $stmt = $pdo->prepare("SELECT * FROM {$table} WHERE report_id = ? ORDER BY {$orderBy}");
        $stmt->execute([$reportId]);
        $bundle[$key] = $stmt->fetchAll();
    }

    return $bundle;
}
