<?php
/**
 * Flexia — Spotify OAuth callback (Authorization Code + PKCE).
 *
 * Esta página la abre Spotify cuando el usuario autoriza la app. Recibe
 * `?code=...&state=...` (o `?error=...`) y es procesada íntegramente en JS:
 *
 *  1. Lee `code_verifier` y `state` de sessionStorage (los guardó el widget al iniciar el flow).
 *  2. Verifica que `state` coincida (CSRF).
 *  3. Hace POST a https://accounts.spotify.com/api/token (intercambio code → tokens).
 *  4. Persiste access/refresh tokens en localStorage del usuario.
 *  5. Notifica a la ventana padre (postMessage + storage event) y se cierra.
 *
 * No requiere lógica server-side: los tokens nunca tocan el backend de Flexia.
 */

$rawUri = isset($_SERVER['REQUEST_URI']) ? (string)$_SERVER['REQUEST_URI'] : '';
$pathOnly = strtok($rawUri, '?') ?: '/spotify-callback.php';
?><!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Conectando Spotify… — Flexia</title>
<meta name="robots" content="noindex,nofollow">
<style>
    :root { color-scheme: dark; }
    html, body { margin: 0; padding: 0; height: 100%; }
    body {
        font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
        background: linear-gradient(145deg, #0c1220 0%, #0a1a14 100%);
        color: #e8f4ff;
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 100vh;
        text-align: center;
        -webkit-font-smoothing: antialiased;
    }
    .card {
        max-width: 420px;
        padding: 28px 32px;
        border-radius: 18px;
        background: rgba(20, 30, 52, 0.7);
        border: 1px solid rgba(120, 200, 255, 0.18);
        backdrop-filter: blur(14px);
        box-shadow: 0 24px 80px rgba(0,0,0,0.45);
    }
    .logo {
        width: 56px; height: 56px;
        margin: 0 auto 14px;
        border-radius: 50%;
        background: #1db954;
        display: flex; align-items: center; justify-content: center;
        font-size: 30px; color: #fff;
        font-weight: bold;
    }
    h1 { font-size: 1.2rem; margin: 0 0 8px; font-weight: 600; }
    p { margin: 6px 0; line-height: 1.5; opacity: .85; font-size: 0.95rem; }
    .spinner {
        margin: 14px auto 0;
        width: 28px; height: 28px;
        border: 3px solid rgba(255,255,255,0.18);
        border-top-color: #1db954;
        border-radius: 50%;
        animation: sp 0.9s linear infinite;
    }
    @keyframes sp { to { transform: rotate(360deg); } }
    .err { color: #ffb4b4; }
    .ok { color: #6ee7b7; }
    .btn {
        display: inline-block;
        margin-top: 14px;
        padding: 10px 18px;
        border-radius: 10px;
        background: #1db954;
        color: #fff;
        text-decoration: none;
        font-weight: 600;
        font-size: 0.9rem;
        border: none;
        cursor: pointer;
    }
    .btn:hover { filter: brightness(1.1); }
</style>
</head>
<body>
<main class="card" role="status">
    <div class="logo" aria-hidden="true">♪</div>
    <h1 id="title">Conectando con Spotify…</h1>
    <p id="msg">Validando autorización, no cierres esta ventana.</p>
    <div class="spinner" id="spinner" aria-hidden="true"></div>
    <button type="button" class="btn" id="closeBtn" style="display:none;">Cerrar ventana</button>
</main>

<script>
(function () {
    'use strict';

    var TITLE = document.getElementById('title');
    var MSG = document.getElementById('msg');
    var SPINNER = document.getElementById('spinner');
    var CLOSE_BTN = document.getElementById('closeBtn');

    var REDIRECT_URI = window.location.origin + <?php echo json_encode($pathOnly, JSON_UNESCAPED_SLASHES); ?>;
    var TOKEN_URL = 'https://accounts.spotify.com/api/token';
    var LS_TOKEN = 'flexia_spotify_token_v1';
    var SS_VERIFIER = 'flexia_spotify_pkce_verifier';
    var SS_STATE = 'flexia_spotify_oauth_state';
    var SS_CLIENT_ID = 'flexia_spotify_oauth_client_id';

    function setError(title, message) {
        TITLE.textContent = title;
        TITLE.className = 'err';
        MSG.textContent = message;
        SPINNER.style.display = 'none';
        CLOSE_BTN.style.display = 'inline-block';
    }

    function setOk(title, message) {
        TITLE.textContent = title;
        TITLE.className = 'ok';
        MSG.textContent = message;
        SPINNER.style.display = 'none';
    }

    CLOSE_BTN.addEventListener('click', function () { window.close(); });

    function readQuery() {
        var out = {};
        (window.location.search || '').replace(/^\?/, '').split('&').forEach(function (pair) {
            if (!pair) return;
            var idx = pair.indexOf('=');
            var k = decodeURIComponent(idx < 0 ? pair : pair.slice(0, idx));
            var v = decodeURIComponent(idx < 0 ? '' : pair.slice(idx + 1));
            out[k] = v;
        });
        return out;
    }

    function notifyParent(payload) {
        try {
            if (window.opener && !window.opener.closed) {
                window.opener.postMessage({ source: 'flexia-spotify', payload: payload }, window.location.origin);
            }
        } catch (_) { /* ignore */ }
    }

    var q = readQuery();

    if (q.error) {
        notifyParent({ ok: false, error: q.error });
        setError('No se pudo conectar', 'Spotify rechazó la autorización: ' + q.error + '.');
        return;
    }

    if (!q.code) {
        setError('Solicitud inválida', 'Falta el parámetro "code". Vuelve al widget e inicia la conexión otra vez.');
        return;
    }

    var savedState = '';
    var verifier = '';
    var clientId = '';
    try {
        savedState = sessionStorage.getItem(SS_STATE) || '';
        verifier = sessionStorage.getItem(SS_VERIFIER) || '';
        clientId = sessionStorage.getItem(SS_CLIENT_ID) || '';
    } catch (_) {}

    if (!verifier || !clientId) {
        setError('Sesión expirada', 'No encontramos la información temporal del navegador. Cierra esta ventana y vuelve a iniciar la conexión desde el widget.');
        return;
    }

    if (savedState && q.state && savedState !== q.state) {
        setError('Verificación fallida', 'El parámetro de seguridad "state" no coincide. Por seguridad, la conexión se canceló.');
        return;
    }

    var body = new URLSearchParams();
    body.set('grant_type', 'authorization_code');
    body.set('code', q.code);
    body.set('redirect_uri', REDIRECT_URI);
    body.set('client_id', clientId);
    body.set('code_verifier', verifier);

    fetch(TOKEN_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: body.toString()
    })
    .then(function (resp) {
        return resp.json().then(function (data) { return { status: resp.status, data: data }; });
    })
    .then(function (r) {
        if (r.status >= 400 || !r.data || !r.data.access_token) {
            var err = (r.data && (r.data.error_description || r.data.error)) || ('HTTP ' + r.status);
            throw new Error(err);
        }
        var record = {
            accessToken: r.data.access_token,
            refreshToken: r.data.refresh_token || '',
            tokenType: r.data.token_type || 'Bearer',
            scope: r.data.scope || '',
            expiresAt: Date.now() + ((Number(r.data.expires_in) || 3600) * 1000) - 30000
        };
        try { localStorage.setItem(LS_TOKEN, JSON.stringify(record)); } catch (_) {}
        try { sessionStorage.removeItem(SS_VERIFIER); sessionStorage.removeItem(SS_STATE); sessionStorage.removeItem(SS_CLIENT_ID); } catch (_) {}

        notifyParent({ ok: true });

        setOk('¡Conectado!', 'Volviendo al escritorio…');
        setTimeout(function () { try { window.close(); } catch (_) {} }, 900);
    })
    .catch(function (e) {
        notifyParent({ ok: false, error: String(e && e.message || e) });
        setError('No se pudo completar la conexión', String(e && e.message || e));
    });
})();
</script>
</body>
</html>
