// PlayerAuth — авторизация плеера.
//
// Поток на проде:
//   1. URL содержит #ticket=<hex>  → POST /auth/redeem-ticket → сохраняем JWT
//   2. Иначе берём JWT из localStorage["player_jwt"], валидируем exp.
//   3. Если ничего нет — `window.location.assign('https://rublox.pro/app')`.
//
// На локалке (localhost) шаг 3 не делаем, чтобы дев-фоллбек по плану
// (раздел 3.3 PLAN.md) работал: пользователь руками кладёт JWT в
// localStorage и перезагружает страницу.
//
// Контракт useAuth() совпадает с тем, что ожидает скопированный
// KubikonPlayer.jsx: { user, isAuthenticated, isLoading, jwt }.

import React, { createContext, useContext, useEffect, useState } from 'react';
import { jwtDecode } from 'jwt-decode';
import {
  redeemTicket,
  saveJWT,
  getJWT,
  clearJWT,
  readTicketFromHash,
  readTeamJwtFromHash,
  clearTicketFromUrl,
} from './ticketExchange';
import { RUBLOX_HOME } from '../api/API';

const PlayerAuthCtx = createContext(null);

const IS_LOCAL =
  typeof window !== 'undefined' &&
  (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');

function decodeJwtSafe(raw) {
  try {
    const payload = jwtDecode(raw);
    if (payload.exp && payload.exp * 1000 < Date.now()) return null;
    return payload;
  } catch (e) {
    return null;
  }
}

export function PlayerAuthProvider({ children }) {
  const [state, setState] = useState({
    user: null,
    isAuthenticated: false,
    isLoading: true,
    jwt: null,
    error: null,
  });

  useEffect(() => {
    let cancelled = false;

    // STANDALONE-режим: пропускаем auth и сразу считаем юзера авторизованным
    // под dummy-id 0. Используется для разработки без бэкенда.
    // Включается через VITE_STANDALONE=true или через ?standalone=1 в URL.
    const env = (typeof import.meta !== 'undefined' && import.meta.env) || {};
    const urlStandalone = typeof window !== 'undefined' &&
        new URLSearchParams(window.location.search).get('standalone') === '1';
    if (String(env.VITE_STANDALONE).toLowerCase() === 'true' || urlStandalone) {
      setState({
        user: { id: 0, firstName: 'Guest', _standalone: true },
        isAuthenticated: true,
        isLoading: false,
        jwt: 'standalone',
        error: null,
      });
      return;
    }

    async function bootstrap() {
      // 0. team_jwt в URL — модератор из team.rublox.pro открывает
      // draft/review-игру для проверки. Просто сохраняем JWT, без
      // redeem-flow: team_jwt и user_jwt подписаны одним секретом, у
      // user-сервиса и storys прозрачно работают (storys проверит
      // moderator-роль через team-flask и пропустит к не-published).
      const teamJwt = readTeamJwtFromHash();
      if (teamJwt) {
        try {
          const payload = decodeJwtSafe(teamJwt);
          if (payload) {
            saveJWT(teamJwt);
            clearTicketFromUrl();
            setState({
              user: { id: payload.id, ...payload, _mod_view: true },
              isAuthenticated: true,
              isLoading: false,
              jwt: teamJwt,
              error: null,
            });
            return;
          }
        } catch (e) {
          clearTicketFromUrl();
          console.warn('[auth] team_jwt decode failed:', e?.message || e);
        }
      }

      // 1. Ticket в URL — самый приоритетный путь.
      const ticket = readTicketFromHash();
      if (ticket) {
        try {
          const res = await redeemTicket(ticket);
          if (cancelled) return;
          if (res && res.jwt) {
            saveJWT(res.jwt);
            clearTicketFromUrl();
            const payload = decodeJwtSafe(res.jwt) || {};
            setState({
              user: res.user || { id: payload.id, ...payload },
              isAuthenticated: true,
              isLoading: false,
              jwt: res.jwt,
              error: null,
            });
            return;
          }
        } catch (e) {
          if (cancelled) return;
          clearTicketFromUrl();
          // Не сваливаемся, а ниже попробуем существующий JWT в localStorage.
          // Если и его нет — отрисуем экран с понятной ошибкой.
          // eslint-disable-next-line no-console
          console.warn('[auth] redeemTicket failed:', e?.message || e);
        }
      }

      // 2. Существующий JWT в localStorage.
      const existing = getJWT();
      if (existing) {
        const payload = decodeJwtSafe(existing);
        if (payload) {
          // На случай dev-fallback (юзер положил JWT через DevTools прямо
          // в player_jwt) — синхронизируем Authorization-зеркало. Иначе
          // engine (читающий 'Authorization') увидит null.
          saveJWT(existing);
          setState({
            user: { id: payload.id, ...payload },
            isAuthenticated: true,
            isLoading: false,
            jwt: existing,
            error: null,
          });
          return;
        }
        clearJWT();
      }

      // 3. Ничего нет. На проде — редирект, на локалке — оставляем заглушку.
      if (cancelled) return;
      if (IS_LOCAL) {
        setState({
          user: null,
          isAuthenticated: false,
          isLoading: false,
          jwt: null,
          error: 'no_jwt_local',
        });
      } else {
        // Сохраняем gameId в return-URL, чтобы после логина можно было
        // вернуть юзера на ту же игру (rublox.pro/app сам разрулит).
        const ret = encodeURIComponent(window.location.pathname);
        window.location.assign(`${RUBLOX_HOME}?return=${ret}`);
      }
    }

    bootstrap();
    return () => { cancelled = true; };
  }, []);

  // Реакция на ручную подмену JWT через DevTools (dev-fallback) —
  // меняем стейт, чтобы перерендерить без F5.
  useEffect(() => {
    if (!IS_LOCAL) return;
    const onStorage = (e) => {
      if (e.key !== 'player_jwt') return;
      const raw = getJWT();
      const payload = raw ? decodeJwtSafe(raw) : null;
      if (payload) {
        setState({
          user: { id: payload.id, ...payload },
          isAuthenticated: true,
          isLoading: false,
          jwt: raw,
          error: null,
        });
      } else {
        setState((s) => ({ ...s, user: null, isAuthenticated: false, jwt: null }));
      }
    };
    window.addEventListener('storage', onStorage);
    return () => window.removeEventListener('storage', onStorage);
  }, []);

  return (
    <PlayerAuthCtx.Provider value={state}>
      {children}
    </PlayerAuthCtx.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(PlayerAuthCtx);
  if (!ctx) {
    return { user: null, isAuthenticated: false, isLoading: false, jwt: null, error: null };
  }
  return ctx;
}
