<?php
/**
 * Conexiune SQLite (PDO) + helpers globali.
 * Migrațiile rulează automat la prima conexiune din request.
 */

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

/**
 * Returnează singleton PDO. La primul apel:
 *  - creează folderul data/ dacă nu există
 *  - activează foreign keys
 *  - rulează migrațiile pendente
 */
function db(): PDO
{
    static $pdo = null;
    if ($pdo instanceof PDO) {
        return $pdo;
    }

    if (!is_dir(DATA_PATH)) {
        if (!@mkdir(DATA_PATH, 0775, true) && !is_dir(DATA_PATH)) {
            http_response_code(500);
            die('Nu pot crea folderul data/. Verifică permisiunile.');
        }
    }

    try {
        $pdo = new PDO('sqlite:' . SQLITE_PATH);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
        $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

        // SQLite tuning
        $pdo->exec('PRAGMA foreign_keys = ON');
        $pdo->exec('PRAGMA journal_mode = WAL');
        $pdo->exec('PRAGMA synchronous = NORMAL');
        $pdo->exec('PRAGMA busy_timeout = 5000');
    } catch (Throwable $e) {
        error_log('[DB] Connection failed: ' . $e->getMessage());
        http_response_code(500);
        die('Eroare conexiune SQLite: ' . htmlspecialchars($e->getMessage()));
    }

    // Auto-migrate o singură dată per request
    static $migrated = false;
    if (!$migrated) {
        $migrated = true;
        try {
            migrate_run($pdo);
        } catch (Throwable $e) {
            error_log('[DB] Migration failed: ' . $e->getMessage());
            http_response_code(500);
            die('Eroare migrație: ' . htmlspecialchars($e->getMessage()));
        }
    }

    return $pdo;
}

// ============================================================
// Query helpers (PDO style — fără $types ca la mysqli)
// ============================================================

/**
 * SELECT cu prepared statement, returnează rândurile.
 */
function db_select(string $sql, array $params = []): array
{
    $stmt = db()->prepare($sql);
    $stmt->execute($params);
    return $stmt->fetchAll();
}

/**
 * INSERT/UPDATE/DELETE — returnează lastInsertId (pentru INSERT) sau rowCount.
 */
function db_exec(string $sql, array $params = []): int
{
    $pdo = db();
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $insertId = (int)$pdo->lastInsertId();
    return $insertId > 0 ? $insertId : $stmt->rowCount();
}

/**
 * Returnează valoarea scalară a primei coloane din primul rând.
 */
function db_scalar(string $sql, array $params = [])
{
    $stmt = db()->prepare($sql);
    $stmt->execute($params);
    $val = $stmt->fetchColumn(0);
    return $val === false ? null : $val;
}

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

function csrf_check(?string $token): bool
{
    return !empty($token)
        && !empty($_SESSION['csrf_token'])
        && hash_equals($_SESSION['csrf_token'], $token);
}

function csrf_field(): string
{
    return '<input type="hidden" name="csrf_token" value="' . htmlspecialchars(csrf_token()) . '">';
}

// ============================================================
// Flash messages
// ============================================================
function flash_set(string $type, string $message): void
{
    $_SESSION['flash'][] = ['type' => $type, 'message' => $message];
}

function flash_get(): array
{
    $f = $_SESSION['flash'] ?? [];
    unset($_SESSION['flash']);
    return $f;
}

// ============================================================
// Output helpers
// ============================================================
function e(?string $v): string
{
    return htmlspecialchars($v ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

function json_response($data, int $code = 200): void
{
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function is_page(string $page): bool
{
    $script = basename($_SERVER['SCRIPT_NAME'] ?? '');
    return $script === $page;
}

function url(string $path = ''): string
{
    return rtrim(APP_BASE_URL, '/') . '/' . ltrim($path, '/');
}

// ============================================================
// Cont activ (context global selectat din header)
// ============================================================
// Aplicația poate avea mai multe conturi eMAG. „Contul activ" e ales din
// dropdown-ul din header și e ținut în sesiune. Valoarea 0 = „Toate conturile".
// Acest context e:
//   - filtru global pe paginile de listă (Produse, Volumetrie, Prețuri)
//   - ținta implicită pentru sync / trimiteri
//
// Helperii de mai jos sunt folosiți în header.php și în paginile de listă.

/**
 * Lista conturilor active (pentru dropdown-ul din header). Cache per request.
 * @return array<int, array{id:int, account_name:string, username:string}>
 */
function active_accounts_list(): array
{
    static $cache = null;
    if ($cache !== null) return $cache;
    try {
        $cache = db_select(
            "SELECT id, account_name, username FROM emag_accounts
             WHERE is_active = 1 ORDER BY account_name COLLATE NOCASE ASC"
        );
    } catch (Throwable $e) {
        $cache = [];
    }
    return $cache;
}

/**
 * ID-ul contului activ selectat din header.
 *   - 0  → „Toate conturile" (fără filtru de cont)
 *   - >0 → un cont anume (validat că există și e activ)
 * Dacă valoarea din sesiune nu mai e validă (cont șters/dezactivat), revine la 0.
 */
function active_account_id(): int
{
    $id = (int)($_SESSION['active_account_id'] ?? 0);
    if ($id <= 0) return 0;
    foreach (active_accounts_list() as $a) {
        if ((int)$a['id'] === $id) return $id;
    }
    return 0; // contul nu mai e activ/valid → fallback la „Toate"
}

/**
 * Setează contul activ în sesiune. $id = 0 înseamnă „Toate conturile".
 */
function set_active_account_id(int $id): void
{
    $_SESSION['active_account_id'] = max(0, $id);
}

// ============================================================
// Setări generale (key→value, tabel app_settings)
// ============================================================

/**
 * Citește o setare. Cache per request. Returnează $default dacă lipsește.
 */
function setting_get(string $key, ?string $default = null): ?string
{
    static $cache = null;
    if ($cache === null) {
        $cache = [];
        try {
            foreach (db_select("SELECT key, value FROM app_settings") as $r) {
                $cache[$r['key']] = $r['value'];
            }
        } catch (Throwable $e) {
            $cache = [];
        }
    }
    return array_key_exists($key, $cache) ? $cache[$key] : $default;
}

/**
 * Salvează o setare (upsert). Invalidează cache-ul nu e necesar în practică
 * (endpoint-urile de save nu re-citesc în același request).
 */
function setting_set(string $key, ?string $value): void
{
    db_exec(
        "INSERT INTO app_settings (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)
         ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP",
        [$key, $value]
    );
}

/**
 * Cota de TVA (procent) ca float, normalizată în intervalul [0, 100].
 * Default 21 dacă setarea lipsește sau e invalidă.
 */
function vat_rate(): float
{
    $v = setting_get('vat_rate', '21');
    $f = is_numeric($v) ? (float)$v : 21.0;
    if ($f < 0)   $f = 0.0;
    if ($f > 100) $f = 100.0;
    return $f;
}

/**
 * Calculează status-ul logic al unei sesiuni de titluri pe baza item-urilor.
 * Folosit la finalize (send-session) și la add-to-session ca să reseteze
 * sesiunile completed/failed la 'draft' sau 'partial' când primesc itemi noi.
 */
function calculate_session_status(int $sessionId): string
{
    $totals = db_select(
        "SELECT sent_status, COUNT(*) AS c FROM title_session_items
         WHERE session_id = ? GROUP BY sent_status",
        [$sessionId]
    );
    $byStatus = [];
    foreach ($totals as $t) {
        $byStatus[$t['sent_status']] = (int)$t['c'];
    }
    $success = $byStatus['success'] ?? 0;
    $failed  = $byStatus['failed']  ?? 0;
    $pending = $byStatus['pending'] ?? 0;

    // Pending = nefinalizat → draft (toate pending) sau partial (mix cu success/failed)
    if ($pending > 0) {
        return ($success > 0 || $failed > 0) ? 'partial' : 'draft';
    }
    if ($success > 0 && $failed === 0) return 'completed';
    if ($success > 0 && $failed > 0)   return 'partial';
    if ($failed > 0)                    return 'failed';
    return 'draft';
}
