<?php
// Anti-cache: asegura que clientes reciban siempre el HTML más reciente
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: 0");

define('VERSION_POS', '3.9.18'); //versión 11-02-2026
include_once( 'include.php' ); // include files
// Fallback de arranque: la zona REAL del usuario la fija pos::__construct al
// leer TIMEZONE_LOCAL de settings (date_default_timezone_set + SET time_zone).
// UTC como base neutra evita asumir Madrid antes de conocer la config.
if (!ini_get('date.timezone')) { date_default_timezone_set('UTC'); }
$pos = new pos();

// === LicenseGate (Tramo 1 ROADMAP_LICENCIAS_TPV.md) ===
// Si el TPV está suspendido (C/DDNS/DEL), mostrar pantalla de licencia
// expirada y salir. Reemplaza al cambio de archivos via templates/reno_pag/.
license_state_machine()->reconcileFromEndDate('public_index_load');
if (!license_gate()->allowPublicIndex()) {
    license_render_blocked_page();
    exit;
}

// Load language file based on POS_LANGUAGE setting
if (POS_LANGUAGE == "spanish" || POS_LANGUAGE == "es-es" || POS_LANGUAGE == "es") {
    include_once ("language/spanish.php");
} elseif (POS_LANGUAGE == "fr" || POS_LANGUAGE == "french") {
    include_once ("language/French.php");
} elseif (POS_LANGUAGE == "en-gb" || POS_LANGUAGE == "english") {
    include_once ("language/english.php");
} elseif (file_exists("language/" . POS_LANGUAGE . ".php")) {
    include_once ("language/" . POS_LANGUAGE . ".php");
} else { // include default: english
    include_once ("language/english.php");
}

$pos->trad_const( $_ );

// === SSO seller flow (spec 2026-05-15-login-flow-design.md) ===
// Si el cliente llega de SSO con permission=11 (vendedor), sso_in.php ya
// pre-autenticó la sesión con caj_pending. Solo falta que elija caja.
if (session_status() !== PHP_SESSION_ACTIVE) { @session_start(); }
$_sso_session_key = "'adm" . (defined('POS_STOREID') ? POS_STOREID : '0') . "'";
$_ssoSession = $_SESSION[$_sso_session_key] ?? null;
$fromSso = !empty($_GET['from_sso'])
    && is_array($_ssoSession)
    && !empty($_ssoSession['caj_pending']);

// TTL del claim caj_pending (10min). Si expiró, invalidamos y forzamos
// re-login. Evita dispositivo abandonado en selector caja.
if ($fromSso && (time() - (int)($_ssoSession['sso_at'] ?? 0)) > 600) {
    unset($_SESSION[$_sso_session_key]);
    header('Location: ' . (defined('HTTPS_SERVER') ? HTTPS_SERVER : '/') . 'tpv/index.php');
    exit;
}

// POST handler: vendedor eligió caja desde el selector
if ($fromSso && $_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['caja'])) {
    $_caja = preg_replace('/[^a-zA-Z0-9_-]/', '', (string)$_POST['caja']);
    if ($_caja === '' || $_caja === 'admin') {
        $_SESSION[$_sso_session_key]['error'] = 'Caja inválida';
    } else {
        $_SESSION[$_sso_session_key]['caj'] = $_caja;
        unset($_SESSION[$_sso_session_key]['caj_pending']);
        unset($_SESSION[$_sso_session_key]['sso_at']);
        session_regenerate_id(true);
        header('Location: ' . (defined('HTTPS_SERVER') ? HTTPS_SERVER : '/') . 'tpv/index.php');
        exit;
    }
}

// Variable global pasada al template para esconder user/pass si caj_pending
$showOnlyTillSelector = $fromSso;
$ssoUserDisplay = $fromSso ? (string)($_ssoSession['suser'] ?? '') : '';

// === Flujo ticket POS vendedor→caja (spec 2026-06-14) ===
// El vendedor llega del admin con ?pos_ticket=. Bajo flag AUTH_UNIFIED,
// resolvemos su nombre SIN consumir el ticket (peek) y activamos el mismo
// "solo selector + nombre" que el flujo SSO. El consumo real ocurre en el
// submit (vía B en session_pos), cuando elige caja.
// RC6: el ticket puede venir por GET (primera llegada desde el admin) o de
// sesión (tras el redirect que lo saca de la URL). La decisión vive en
// pos_ticket_resolve() para poder probarla sin sesión ni cabeceras.
if (empty($_SESSION)) { @session_start(); }
$_posTicketRes    = pos_ticket_resolve($_GET, $_SESSION["'" . POS_STOREID . "'"] ?? []);
$posTicket        = $_posTicketRes['ticket'];
$posTicketFromUrl = $_posTicketRes['fromUrl'];
if ($posTicket !== '' && !$showOnlyTillSelector) {
    require_once __DIR__ . '/../api/v1/classes/auth/AuthServiceFactory.php';
    if (\AuthServiceFactory::isUnified()) {
        require_once __DIR__ . '/../api/v1/classes/auth/AuthStore.php';
        require_once __DIR__ . '/../api/v1/classes/auth/AuthResult.php';
        require_once __DIR__ . '/../api/v1/classes/auth/MysqliAuthStore.php';
        require_once __DIR__ . '/../api/v1/classes/auth/AuthService.php';
        $svc = \AuthServiceFactory::fromLegacyDb($pos->session_pos->db, DB_PREFIX);
        $peekUid = $svc->peekPosTicket($posTicket);
        if ($peekUid !== null) {
            $showOnlyTillSelector = true;
            $ssoUserDisplay = (string) $pos->session_pos->idto_username($peekUid);
            $posTicketForForm = $posTicket; // lo recoge el template como hidden
            // Entrada fresca del vendedor por ticket (GET, sin submit): NO debe
            // heredar un error pegado en sesión de un intento anterior (p.ej.
            // "caja usada por otro"). Se limpia para no pintarlo en el selector.
            unset($_SESSION["'" . POS_STOREID . "'"]['error']);

            // RC6: sacar el ticket de la URL. Vive en access logs, proxies,
            // historial y cabecera Referer durante todo su TTL (300 s). Tras
            // validarlo por peek lo guardamos en sesión y redirigimos a una URL
            // limpia: el valor consumible deja de persistir en el historial del
            // navegador. El consumo real sigue siendo en el submit (POST).
            if ($posTicketFromUrl) {
                if (empty($_SESSION)) { @session_start(); }
                $_SESSION["'" . POS_STOREID . "'"]['pos_ticket_pending'] = $posTicket;
                header('Location: index.php', true, 303);
                exit;
            }
        }
    }
}
if (!isset($posTicketForForm)) {
    $posTicketForForm = '';
}

$t[ 'loggedin' ] = $pos->session_pos->loggedIn($pos);

// PRG (auditoría 2026-06-17): si esto fue un POST de login (acertado o
// fallido), loggedIn() ya aplicó todos los efectos (abrir caja, cookie,
// regenerar sesión, o grabar el error en sesión). Redirigimos a un GET limpio
// para que Atrás/Recargar NO reenvíe user/password/caja ("Confirmar reenvío
// del formulario"). El estado (login OK o mensaje de error) viaja por
// sesión/cookie, así que el GET posterior repinta lo correcto.
if ( pos_login_should_redirect( $_POST, $_SERVER['REQUEST_METHOD'] ?? 'GET' ) ) {
	$_dest = ( defined('HTTPS_SERVER') && !empty(HTTPS_SERVER) ) ? HTTPS_SERVER . 'tpv/index.php' : 'index.php';
	header( 'Location: ' . $_dest, true, 303 );
	exit;
}

if ( !empty( $_SESSION[ "'" . POS_STOREID . "'" ][ 'error' ] ) ) {
	$_[ 'login_error_show' ] = $_SESSION[ "'" . POS_STOREID . "'" ][ 'error' ];
}else {
	$_[ 'login_error_show' ] = "";
}
if ( empty( $t[ 'loggedin' ] )) {
	include( "templates/login.php" );
}else {
	if ( empty( $_GET[ 'rt' ] ) ) {
		include_once( "templates/template.php" );
	} else {
		if ( $_GET['rt'] == "r_vent" ) {
			include_once( "templates/template_v.php" );
		}
	}
}
