/**
 * useWorldCupFixtures — Phase-2 live-data wiring (FEATURE 2026-06).
 *
 * Fetches World-Cup fixtures from the PHP proxy
 * (`api/sports/fixtures.php`) and normalises them into the exact
 * `Match` shape the WorldCup UI already understands
 * (`@/lib/worldCupData`).
 *
 * Endpoint resolution
 * ───────────────────
 *   • Configurable via the `REACT_APP_API_BASE` env var so the backend
 *     domain can be migrated without rebuilding the React code.
 *   • Defaults to the production proxy when the var is unset.
 *
 *     REACT_APP_API_BASE=https://prmtly.com/api/sports/fixtures.php
 *
 * Robust fallback (→ MOCK_MATCHES)
 * ────────────────────────────────
 * The hook falls back to the bundled `MOCK_MATCHES` whenever the app
 * cannot show *live* content for ANY reason, i.e. when:
 *   1. the request errors / times out / is non-2xx, OR
 *   2. the payload reports `configured: false` (admin hasn't wired the
 *      upstream API key yet), OR
 *   3. the payload is valid but its `matches` array is empty
 *      (no fixtures scheduled) — keeps the UI populated + engaging.
 *
 * In every fallback case `source === "mock"`; on success it is `"live"`.
 */
import { useCallback, useEffect, useRef, useState } from "react";
import {
  MOCK_MATCHES,
  type Match,
  type MatchStatus,
  type Team,
} from "@/lib/worldCupData";

/** Default production proxy. */
const DEFAULT_API_BASE = "https://prmtly.com/api/sports/fixtures.php";

const _env = (import.meta as { env?: Record<string, string | undefined> }).env ?? {};
const _backend = (_env.VITE_BACKEND_URL || _env.REACT_APP_BACKEND_URL || "").trim();

/**
 * Prefer backend-managed fixtures endpoint so admin match edits can trigger
 * automatic push notifications. Falls back to the legacy PHP proxy.
 */
const API_BASE: string =
  (_env.REACT_APP_API_BASE || _env.VITE_API_BASE || "").trim() ||
  (_backend ? `${_backend.replace(/\/$/, "")}/api/worldcup/fixtures` : "") ||
  DEFAULT_API_BASE;

/** Abort the request if the proxy is slow/unresponsive. */
const REQUEST_TIMEOUT_MS = 8000;

export type FixturesSource = "live" | "mock";

/** A single row in a group standings table (Football-Data.org). */
export interface StandingRow {
  position: number;
  name: string;
  code: string;
  crest?: string;
  played: number;
  won: number;
  draw: number;
  lost: number;
  gf: number;
  ga: number;
  gd: number;
  points: number;
  form?: string | null;
}
export interface StandingGroup {
  group: string;
  table: StandingRow[];
}

export interface UseWorldCupFixturesResult {
  /** Normalised fixtures — live when available, else the mock dataset. */
  matches: Match[];
  /** Group standings tables (only when the data source provides them). */
  standings: StandingGroup[];
  /** Where `matches` came from. Useful for a tiny "LIVE / DEMO" badge. */
  source: FixturesSource;
  /** True only during the very first in-flight request. */
  loading: boolean;
  /** Human-readable reason we fell back to mock data (null on success). */
  error: string | null;
  /** Manually re-run the fetch (e.g. pull-to-refresh / focus). */
  refetch: () => void;
}

/* ──────────────────────────────────────────────────────────────────
 * Raw proxy payload (tolerant — every field is optional so a partial
 * or slightly-different backend response never throws).
 * ────────────────────────────────────────────────────────────────── */
type RawTeam = { name?: string; code?: string } | string | null | undefined;

interface RawMatch {
  id?: string | number;
  home?: RawTeam;
  away?: RawTeam;
  homeScore?: number | string | null;
  awayScore?: number | string | null;
  status?: string;
  /** Documented field name. */
  kickoff?: string;
  /** Tolerated alias (matches the mock shape). */
  kickoffIso?: string;
  /** Richer fields the proxy may add later — passed through if present. */
  group?: string;
  round?: string;
  venue?: string;
  broadcaster?: string;
  liveLabel?: string;
  homePenalty?: number;
  awayPenalty?: number;
}

interface ApiResponse {
  configured?: boolean;
  matches?: RawMatch[];
  standings?: StandingGroup[];
  source?: string;
}

/* ──────────────────────────────────────────────────────────────────
 * Country-name → ISO-3166-1 alpha-2 (lower-case) for flag resolution.
 * The proxy payload exposes team *names* only; the UI resolves flags
 * from `team.code` via flagcdn.com, so we map names → codes here.
 * Unknown names degrade gracefully to "" (flag simply doesn't load).
 * ────────────────────────────────────────────────────────────────── */
const COUNTRY_CODES: Record<string, string> = {
  argentina: "ar",
  australia: "au",
  belgium: "be",
  brazil: "br",
  cameroon: "cm",
  canada: "ca",
  colombia: "co",
  "costa rica": "cr",
  croatia: "hr",
  denmark: "dk",
  ecuador: "ec",
  egypt: "eg",
  england: "gb-eng",
  france: "fr",
  germany: "de",
  ghana: "gh",
  greece: "gr",
  iran: "ir",
  italy: "it",
  japan: "jp",
  "korea rep.": "kr",
  "korea republic": "kr",
  "south korea": "kr",
  mexico: "mx",
  morocco: "ma",
  netherlands: "nl",
  nigeria: "ng",
  norway: "no",
  poland: "pl",
  portugal: "pt",
  qatar: "qa",
  "saudi arabia": "sa",
  scotland: "gb-sct",
  senegal: "sn",
  serbia: "rs",
  spain: "es",
  sweden: "se",
  switzerland: "ch",
  tunisia: "tn",
  turkey: "tr",
  ukraine: "ua",
  uruguay: "uy",
  usa: "us",
  "united states": "us",
  wales: "gb-wls",
};

const toCode = (name: string, explicit?: string): string => {
  if (explicit && explicit.trim()) return explicit.trim().toLowerCase();
  return COUNTRY_CODES[name.trim().toLowerCase()] ?? "";
};

const normTeam = (raw: RawTeam): Team => {
  if (typeof raw === "string") {
    return { name: raw, code: toCode(raw) };
  }
  const name = raw?.name?.trim() || "TBD";
  return { name, code: toCode(name, raw?.code) };
};

const normStatus = (raw?: string): MatchStatus => {
  const s = (raw || "").trim().toUpperCase();
  if (s === "LIVE" || s === "IN_PLAY" || s === "INPLAY" || s === "1H" || s === "2H" || s === "HT") {
    return "LIVE";
  }
  if (s === "FT" || s === "FINISHED" || s === "FULL_TIME" || s === "FULLTIME" || s === "AET" || s === "PEN") {
    return "FT";
  }
  return "UPCOMING";
};

const toScore = (v: number | string | null | undefined): number | null => {
  if (v === null || v === undefined || v === "") return null;
  const n = typeof v === "number" ? v : parseInt(v, 10);
  return Number.isFinite(n) ? n : null;
};

/** Map ONE raw proxy fixture into the UI's `Match` shape. */
const normalizeMatch = (raw: RawMatch, idx: number): Match => {
  const status = normStatus(raw.status);
  const kickoffIso = (raw.kickoffIso || raw.kickoff || "").trim();
  // Scores are only meaningful once a match is under way / finished.
  const homeScore = status === "UPCOMING" ? null : toScore(raw.homeScore);
  const awayScore = status === "UPCOMING" ? null : toScore(raw.awayScore);

  return {
    id: String(raw.id ?? `live-${idx}`),
    kickoffIso,
    status,
    liveLabel: raw.liveLabel,
    group: raw.group,
    round: raw.round as Match["round"],
    venue: raw.venue ?? "",
    home: normTeam(raw.home),
    away: normTeam(raw.away),
    homeScore,
    awayScore,
    homePenalty: raw.homePenalty,
    awayPenalty: raw.awayPenalty,
    broadcaster: raw.broadcaster,
  };
};

/**
 * Live-data hook for the WorldCup page.
 *
 * @param pollMs When > 0, re-fetches on this interval (live scores).
 *               Defaults to 0 (no polling).
 */
export function useWorldCupFixtures(pollMs = 0): UseWorldCupFixturesResult {
  const [matches, setMatches] = useState<Match[]>(MOCK_MATCHES);
  const [standings, setStandings] = useState<StandingGroup[]>([]);
  const [source, setSource] = useState<FixturesSource>("mock");
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  const [reloadTick, setReloadTick] = useState(0);

  // Avoid setting state after unmount (StrictMode / fast navigation).
  const mounted = useRef(true);

  const refetch = useCallback(() => setReloadTick((t) => t + 1), []);

  useEffect(() => {
    mounted.current = true;

    const fallback = (reason: string) => {
      if (!mounted.current) return;
      setMatches(MOCK_MATCHES);
      setSource("mock");
      setError(reason);
    };

    const run = async () => {
      const controller = new AbortController();
      const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
      try {
        const res = await fetch(API_BASE, {
          method: "GET",
          headers: { Accept: "application/json" },
          signal: controller.signal,
        });

        if (!res.ok) {
          fallback(`HTTP ${res.status}`);
          return;
        }

        const data = (await res.json()) as ApiResponse;

        // Rule 2 — backend not yet configured.
        if (data?.configured === false) {
          fallback("API reported configured: false");
          return;
        }

        const rawList = Array.isArray(data?.matches) ? data.matches : [];
        const live = rawList.map(normalizeMatch);

        // Rule 3 — valid response, but nothing to show.
        if (live.length === 0) {
          fallback("API returned no matches");
          return;
        }

        if (!mounted.current) return;
        setMatches(live);
        setStandings(Array.isArray(data?.standings) ? data.standings : []);
        setSource("live");
        setError(null);
      } catch (e) {
        // Rule 1 — network error / timeout / bad JSON.
        const reason =
          e instanceof DOMException && e.name === "AbortError"
            ? "Request timed out"
            : e instanceof Error
              ? e.message
              : "Network error";
        fallback(reason);
      } finally {
        clearTimeout(timer);
        if (mounted.current) setLoading(false);
      }
    };

    run();

    let interval: ReturnType<typeof setInterval> | undefined;
    if (pollMs > 0) {
      interval = setInterval(run, pollMs);
    }

    return () => {
      mounted.current = false;
      if (interval) clearInterval(interval);
    };
  }, [pollMs, reloadTick]);

  return { matches, standings, source, loading, error, refetch };
}

export default useWorldCupFixtures;
