<?php
declare(strict_types=1);
require_once __DIR__ . '/config.php';
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_name('WEBSISCRE_SESSION');
    session_start();
}

function db(bool $withoutDb = false): mysqli {
    static $connections = [];
    $key = $withoutDb ? 'server' : 'app';
    if (!isset($connections[$key])) {
        mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
        $connections[$key] = new mysqli(DB_HOST, DB_USER, DB_PASS, $withoutDb ? null : DB_NAME);
        $connections[$key]->set_charset('utf8mb4');
    }
    return $connections[$key];
}
function e(mixed $v): string { return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }
function url(string $path = ''): string { return BASE_URL . ($path ? '/' . ltrim($path, '/') : ''); }
function redirect(string $path): never { header('Location: ' . url($path)); exit; }
function csrf(): string { return $_SESSION['csrf'] ??= bin2hex(random_bytes(24)); }
function check_csrf(): void { if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) throw new RuntimeException('La sesión del formulario venció. Vuelva a intentarlo.'); }
function flash(string $type, string $text): void { $_SESSION['flash'][] = [$type, $text]; }
function user(): ?array { return $_SESSION['user'] ?? null; }
function require_login(): void { if (!user()) redirect('login.php'); }

function menu_registry(): array {
    return [
        'dashboard'=>['Inicio','fa-house','index.php','Inicio'],
        'clientes'=>['Clientes','fa-users','app.php?p=clientes','Mantenimiento'],
        'vendedores'=>['Vendedores','fa-user-tie','app.php?p=catalogo&t=vendedores','Mantenimiento'],
        'canales'=>['Canales de Venta','fa-route','app.php?p=catalogo&t=canales_venta','Mantenimiento'],
        'tipos_documento'=>['Tipos de Documento','fa-file-lines','app.php?p=catalogo&t=tipos_documento','Mantenimiento'],
        'garantias'=>['Garantías','fa-shield-halved','app.php?p=catalogo&t=garantias','Mantenimiento'],
        'tasas_descuento'=>['Tasas Descuento','fa-percent','app.php?p=tasas&t=tasas_descuento','Parámetros'],
        'tasas_cuotas'=>['Tasas Préstamo Cuotas','fa-chart-line','app.php?p=tasas&t=tasas_cuotas','Parámetros'],
        'bancos'=>['Bancos','fa-building-columns','app.php?p=catalogo&t=bancos','Mantenimiento'],
        'clases_prestamo'=>['Clases de Préstamo','fa-tags','app.php?p=catalogo&t=clases_prestamo','Mantenimiento'],
        'tae_limites'=>['TAE Límite','fa-calendar-check','app.php?p=tae','Parámetros'],
        'tasa_seguro'=>['Tasa Seguro','fa-shield','app.php?p=rangos&t=tasa_seguro','Parámetros'],
        'gastos_administrativos'=>['Tasa Gastos Administrativos','fa-receipt','app.php?p=rangos&t=gastos_administrativos','Parámetros'],
        'gastos_cobranza'=>['Tasa Gastos de Cobranza','fa-file-invoice-dollar','app.php?p=rangos&t=gastos_cobranza','Parámetros'],
        'limite_operativo'=>['Límite Gastos Operativos BCP','fa-landmark','app.php?p=limite_operativo','Parámetros'],
        'parametros_generales'=>['Parámetros Generales','fa-sliders','app.php?p=parametros_generales','Parámetros'],
        'parametros_empresa'=>['Parámetros Empresa','fa-building','app.php?p=parametros_empresa','Parámetros'],
        'borrado_especial'=>['Eliminar Operación','fa-trash-can','app.php?p=borrado_especial','Mantenimiento'],
        'eliminar_capital'=>['Eliminar Capital','fa-trash-can','app.php?p=eliminar_capital','Mantenimiento'],
        'importar_datos'=>['Importar Datos','fa-file-import','app.php?p=importar_datos','Mantenimiento'],
        'operaciones'=>['Descuento de Documento','fa-hand-holding-dollar','app.php?p=operaciones','Operaciones'],
        'carga_capital'=>['Carga Capital','fa-sack-dollar','app.php?p=carga_capital','Operaciones'],
        'informe_clientes'=>['Informe de Clientes','fa-chart-column','app.php?p=informe_clientes','Informes'],
        'inventario_cartera'=>['Inventario de Cartera','fa-warehouse','app.php?p=inventario_cartera','Informes'],
        'cheques_depositar'=>['Lista de Cheques a Depositar','fa-money-check-dollar','app.php?p=cheques_depositar','Informes'],
        'reporte_capitales'=>['Reporte Capitales','fa-chart-pie','app.php?p=reporte_capitales','Informes'],
        'detalle_capitales'=>['Detalle Capitales','fa-list-ol','app.php?p=detalle_capitales','Informes'],
        'caja'=>['Caja / Cobros','fa-cash-register','app.php?p=caja','Caja'],
        'pago_capitales'=>['Pago Capitales','fa-money-bill-transfer','app.php?p=pago_capitales','Caja'],
        'usuarios'=>['Usuarios','fa-user-lock','app.php?p=usuarios','Seguridad'],
        'roles'=>['Roles y Permisos','fa-key','app.php?p=roles','Seguridad'],
    ];
}
function sync_permissions(): void {
    $cn=db();
    $cn->query("CREATE TABLE IF NOT EXISTS permisos (id INT AUTO_INCREMENT PRIMARY KEY, clave VARCHAR(80) UNIQUE, nombre VARCHAR(120), grupo_menu VARCHAR(80), ruta VARCHAR(255), activo TINYINT DEFAULT 1) ENGINE=InnoDB");
    $cn->query("CREATE TABLE IF NOT EXISTS rol_permisos (rol_id INT, permiso_id INT, PRIMARY KEY(rol_id,permiso_id)) ENGINE=InnoDB");
    $st=$cn->prepare("INSERT INTO permisos(clave,nombre,grupo_menu,ruta,activo) VALUES(?,?,?,?,1) ON DUPLICATE KEY UPDATE nombre=VALUES(nombre),grupo_menu=VALUES(grupo_menu),ruta=VALUES(ruta),activo=1");
    foreach(menu_registry() as $key=>$m){$st->bind_param('ssss',$key,$m[0],$m[3],$m[2]);$st->execute();}
    $keys=array_keys(menu_registry());$quoted=implode(',',array_map(fn($k)=>"'".$cn->real_escape_string($k)."'",$keys));$cn->query("UPDATE permisos SET activo=0 WHERE clave NOT IN ($quoted)");
    $cn->query("INSERT IGNORE INTO rol_permisos SELECT r.id,p.id FROM roles r JOIN permisos p WHERE r.es_admin=1");
}
function allowed(string $key): bool {
    if (!user()) return false;
    if (empty(user()['rol_id']) && !empty(user()['id'])) {
        $uid=(int)user()['id'];
        $st=db()->prepare("SELECT u.rol_id,r.nombre rol FROM usuarios u JOIN roles r ON r.id=u.rol_id WHERE u.id=? AND u.activo=1 AND r.activo=1");
        $st->bind_param('i',$uid);$st->execute();$fresh=$st->get_result()->fetch_assoc();
        if(!$fresh)return false;
        $_SESSION['user']['rol_id']=(int)$fresh['rol_id'];
        $_SESSION['user']['rol']=$fresh['rol'];
    }
    $admin=db()->prepare("SELECT es_admin FROM roles WHERE id=? AND activo=1");
    $rid=(int)user()['rol_id'];$admin->bind_param('i',$rid);$admin->execute();
    if(!empty($admin->get_result()->fetch_assoc()['es_admin']))return true;
    $st=db()->prepare("SELECT 1 FROM rol_permisos rp JOIN permisos p ON p.id=rp.permiso_id WHERE rp.rol_id=? AND p.clave=? AND p.activo=1");
    $st->bind_param('is',$rid,$key); $st->execute(); return (bool)$st->get_result()->fetch_row();
}
function require_permission(string $key): void { require_login(); if(!allowed($key)){http_response_code(403); exit('Acceso denegado');} }
function audit(string $action, string $table='', ?int $id=null, string $detail=''): void {
    $uid=(int)(user()['id']??0); $ip=$_SERVER['REMOTE_ADDR']??'';
    $st=db()->prepare("INSERT INTO auditoria(usuario_id,accion,tabla_afectada,registro_id,detalle,ip) VALUES(NULLIF(?,0),?,?,?,?,?)");
    $st->bind_param('ississ',$uid,$action,$table,$id,$detail,$ip); $st->execute();
}
function money(float $v): string { return number_format($v, 0, ',', '.'); }
function general_params(): array {
    static $p=null;
    if($p===null)$p=db()->query("SELECT * FROM parametros_generales WHERE id=1")->fetch_assoc()?:[];
    return $p;
}
function loan_divisor(): float { return max(1,(float)(general_params()['divisor_prestamo']??365))*100; }
function money_currency(float $value, array|string|null $currency=null): string {
    if(is_string($currency)){$code=$currency;$decimals=$code==='USD'?2:0;$symbol=$code==='USD'?'US$':'Gs.';}
    else{$code=(string)($currency['codigo']??'PYG');$decimals=(int)($currency['decimales']??($code==='USD'?2:0));$symbol=(string)($currency['simbolo']??($code==='USD'?'US$':'Gs.'));}
    return $symbol.' '.number_format($value,$decimals,',','.');
}
