/**
 * FootApi adapter — BACKUP soccer data source (Session 9).
 *
 * Wraps the RapidAPI-hosted FootApi service (Sofascore mirror). Used
 * as the fallback when api-football.com is rate-limited or returns
 * thin data. Free tier: 50 requests/day.
 *
 * Auth: RapidAPI headers (x-rapidapi-key + x-rapidapi-host). DO NOT
 * use the x-apisports-key header here — that's the primary adapter.
 *
 * Env:
 *   RAPID_API_KEY  — RapidAPI marketplace key (shared across Tank01 + FootApi)
 *   FOOTAPI_HOST   — host header (defaults to footapi7.p.rapidapi.com)
 *
 * Rate limit:
 *   Hard 50 req/day. We track in `footapi:daily_count` (24h TTL) and
 *   stop at 45 — same 5-req safety margin as the primary adapter
 *   (smaller absolute margin because the daily budget is smaller).
 *
 * Tournament IDs used in the URL paths:
 *   16 — FIFA World Cup
 *   (others discovered via the schedule endpoint as needed)
 */

const axios = require('axios');
const { cacheGet, cacheSet } = require('../../utils/redis');

const HTTP_TIMEOUT_MS = 8_000;

const TTL = Object.freeze({
  lineups:   24 * 3600,
  incidents: 12 * 3600,
  referee:    7 * 24 * 3600,  // 7d — referee stats move slowly
  schedule:   6 * 3600,
});

const DAILY_LIMIT = 50;
const SAFETY_MARGIN = 5;
const SOFT_LIMIT = DAILY_LIMIT - SAFETY_MARGIN; // 45
const DAILY_COUNTER_KEY = 'footapi:daily_count';
const DAILY_TTL_SEC = 24 * 3600;

const WC_TOURNAMENT_ID = 16;

function getHost() {
  return process.env.FOOTAPI_HOST || 'footapi7.p.rapidapi.com';
}

function hasApiKey() {
  return !!process.env.RAPID_API_KEY;
}

async function readDailyCount() {
  const v = await cacheGet(DAILY_COUNTER_KEY);
  if (v == null) return 0;
  const n = typeof v === 'number' ? v : Number(v);
  return Number.isFinite(n) ? n : 0;
}

async function bumpDailyCount() {
  const next = (await readDailyCount()) + 1;
  await cacheSet(DAILY_COUNTER_KEY, next, DAILY_TTL_SEC);
  return next;
}

async function fetchWithCache(path, cacheKey, ttl) {
  const fresh = await cacheGet(cacheKey);
  if (fresh !== null) return fresh;
  if (!hasApiKey()) return null;

  const used = await readDailyCount();
  if (used >= SOFT_LIMIT) {
    const stale = await cacheGet(`${cacheKey}:stale`);
    if (stale !== null) return stale;
    return null;
  }

  try {
    const host = getHost();
    const res = await axios.get(`https://${host}${path}`, {
      headers: {
        'x-rapidapi-key': process.env.RAPID_API_KEY,
        'x-rapidapi-host': host,
      },
      timeout: HTTP_TIMEOUT_MS,
    });
    await bumpDailyCount();
    const body = res.data;
    if (body && typeof body === 'object') {
      await cacheSet(cacheKey, body, ttl);
      await cacheSet(`${cacheKey}:stale`, body, ttl * 4);
    }
    return body;
  } catch (err) {
    console.warn('[footApi] fetch failed:', path, err.message);
    const stale = await cacheGet(`${cacheKey}:stale`);
    if (stale !== null) return stale;
    return null;
  }
}

// ---- Public surface ----

/**
 * getMatchLineups — players with minutesPlayed and the 28-key stats
 * block FootApi exposes per player (rating, shots, passes, tackles,
 * goals, assists, cards, etc.).
 */
async function getMatchLineups(matchId) {
  if (!matchId) return null;
  const data = await fetchWithCache(
    `/api/match/${matchId}/lineups`,
    `footapi:match:${matchId}:lineups`,
    TTL.lineups,
  );
  if (data === null) return null;
  // The FootApi response carries `home` and `away` sides, each with
  // `players` arrays. Flatten so callers don't need to reach into
  // upstream-specific structure.
  const out = [];
  for (const side of ['home', 'away']) {
    const team = data?.[side];
    if (!team || !Array.isArray(team.players)) continue;
    for (const entry of team.players) {
      const p = entry?.player || {};
      const stats = entry?.statistics || {};
      out.push({
        team: team.formation ? `${side}(${team.formation})` : side,
        side,
        playerId: p.id ?? null,
        name: p.name ?? null,
        position: entry.position ?? null,
        shirtNumber: entry.shirtNumber ?? null,
        substitute: !!entry.substitute,
        captain: !!entry.captain,
        minutesPlayed: stats.minutesPlayed ?? null,
        rating: stats.rating ?? null,
        goals: stats.goals ?? 0,
        assists: stats.goalAssist ?? 0,
        shots: stats.totalShots ?? 0,
        shotsOnTarget: stats.shotOnTarget ?? 0,
        passes: stats.totalPass ?? 0,
        accuratePasses: stats.accuratePass ?? 0,
        tackles: stats.totalTackle ?? 0,
        yellow: stats.yellowCards ?? 0,
        red: stats.redCards ?? 0,
        saves: stats.saves ?? null,
        keyPasses: stats.keyPass ?? 0,
      });
    }
  }
  return out;
}

/**
 * getMatchIncidents — minute-by-minute goals, cards, subs. The
 * minute + addedTime carry detail the events feed needs for trap
 * detection (e.g. late-game cards inflate referee_card_bias signal).
 */
async function getMatchIncidents(matchId) {
  if (!matchId) return null;
  const data = await fetchWithCache(
    `/api/match/${matchId}/incidents`,
    `footapi:match:${matchId}:incidents`,
    TTL.incidents,
  );
  if (data === null) return null;
  const list = data?.incidents;
  if (!Array.isArray(list)) return [];
  return list.map((i) => ({
    type: i.incidentType ?? null,
    classType: i.incidentClass ?? null,
    minute: i.time ?? null,
    addedTime: i.addedTime ?? null,
    isHome: i.isHome ?? null,
    player: i.player?.name ?? null,
    assist: i.assist1?.name ?? null,
    text: i.text ?? null,
  }));
}

/**
 * getRefereeStatistics — referee card + appearance history per
 * tournament. The shape `{ yellowCards, redCards, appearances }`
 * feeds the soccer-trap `referee_card_bias` signal.
 */
async function getRefereeStatistics(refereeId) {
  if (!refereeId) return null;
  const data = await fetchWithCache(
    `/api/referee/${refereeId}/statistics`,
    `footapi:referee:${refereeId}:stats`,
    TTL.referee,
  );
  if (data === null) return null;
  const stats = data?.statistics;
  if (!Array.isArray(stats)) return [];
  return stats.map((s) => ({
    tournamentId: s.tournament?.id ?? null,
    tournamentName: s.tournament?.name ?? null,
    season: s.season?.year ?? null,
    appearances: s.appearances ?? 0,
    yellowCards: s.yellowCards ?? 0,
    redCards: s.redCards ?? 0,
    yellowCardsPerGame: s.appearances > 0 ? Math.round((s.yellowCards / s.appearances) * 100) / 100 : null,
    redCardsPerGame: s.appearances > 0 ? Math.round((s.redCards / s.appearances) * 1000) / 1000 : null,
  }));
}

/**
 * getWorldCupSchedule — fixtures for a date. Tournament ID 16 is
 * the FIFA World Cup; the path is `/api/tournament/16/schedules/dd/mm/yyyy`.
 */
async function getWorldCupSchedule(day, month, year) {
  if (!day || !month || !year) return null;
  const dateKey = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
  const data = await fetchWithCache(
    `/api/tournament/${WC_TOURNAMENT_ID}/schedules/${day}/${month}/${year}`,
    `footapi:wc:schedule:${dateKey}`,
    TTL.schedule,
  );
  if (data === null) return null;
  const list = data?.events;
  if (!Array.isArray(list)) return [];
  return list.map((e) => ({
    id: e.id ?? null,
    startTimestamp: e.startTimestamp ?? null,
    status: e.status?.type ?? null,
    homeTeam: e.homeTeam?.name ?? null,
    awayTeam: e.awayTeam?.name ?? null,
    homeTeamId: e.homeTeam?.id ?? null,
    awayTeamId: e.awayTeam?.id ?? null,
    homeScore: e.homeScore?.current ?? null,
    awayScore: e.awayScore?.current ?? null,
    venue: e.venue?.name ?? null,
    referee: e.referee?.name ?? null,
  }));
}

module.exports = {
  getMatchLineups,
  getMatchIncidents,
  getRefereeStatistics,
  getWorldCupSchedule,
  hasApiKey,
  __internals: {
    TTL,
    DAILY_LIMIT,
    SOFT_LIMIT,
    DAILY_COUNTER_KEY,
    WC_TOURNAMENT_ID,
    readDailyCount,
    bumpDailyCount,
    getHost,
    resetCounterForTests: async () => cacheSet(DAILY_COUNTER_KEY, 0, DAILY_TTL_SEC),
  },
};
