// 백엔드 FastAPI 클라이언트. 동일 출처 /api (dev=vite proxy, prod=nginx proxy).
import type {
  Comment,
  CommentList,
  CrowdStats,
  Leaderboard,
  Match,
  ModelName,
  MyPrediction,
} from "./types";
import type { Lang } from "./i18n";

const BASE = import.meta.env.VITE_API_BASE || "/api";

async function http<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    headers: { "Content-Type": "application/json", ...(init?.headers || {}) },
    ...init,
  });
  if (!res.ok) {
    let detail = res.statusText;
    try {
      const body = await res.json();
      detail = body.detail || detail;
    } catch {
      /* noop */
    }
    throw new ApiError(res.status, detail);
  }
  return res.json() as Promise<T>;
}

export class ApiError extends Error {
  constructor(
    public status: number,
    public detail: string,
  ) {
    super(detail);
  }
}

export function listMatches(lang: Lang): Promise<Match[]> {
  return http<Match[]>(`/matches?lang=${lang}`);
}

export function getMatch(matchId: string, lang: Lang): Promise<Match> {
  return http<Match>(`/matches/${matchId}?lang=${lang}`);
}

export interface SubmitResult {
  ok: boolean;
  predictionId: string;
  matchedModels: ModelName[];
  exactMatch: boolean;
  crowd: CrowdStats;
}

export function submitPrediction(body: {
  matchId: string;
  deviceId: string;
  outcome: string;
  scoreA: number;
  scoreB: number;
  email?: string;
  notify: boolean;
}): Promise<SubmitResult> {
  return http<SubmitResult>(`/predictions`, {
    method: "POST",
    body: JSON.stringify(body),
  });
}

export function getLeaderboard(): Promise<Leaderboard> {
  return http<Leaderboard>(`/leaderboard`);
}

// 내 지난 예측 — 이메일 기준 조회(로그인 없음). 최신순. 빈 이메일이면 빈 배열.
export function fetchMyPredictions(email: string): Promise<MyPrediction[]> {
  const e = email.trim();
  if (!e) return Promise.resolve([]);
  return http<MyPrediction[]>(`/predictions/mine?email=${encodeURIComponent(e)}`);
}

// ── 댓글(경기별 한마디) — 완전 익명 ──
export function listComments(
  matchId: string,
  limit: number,
  offset: number,
): Promise<CommentList> {
  return http<CommentList>(
    `/matches/${matchId}/comments?limit=${limit}&offset=${offset}`,
  );
}

export function postComment(
  matchId: string,
  body: { deviceId: string; nickname: string; body: string },
): Promise<Comment> {
  return http<Comment>(`/matches/${matchId}/comments`, {
    method: "POST",
    body: JSON.stringify(body),
  });
}

// ── 세션 닉네임: 세션당 한 번 발급받아 sessionStorage 에 캐싱 ──
// 탭/창을 닫으면 비워지고(껐다 켜면 새 닉), 시크릿창은 별도 저장소라 새로 발급됨.
const SESSION_NICK_KEY = "tp_session_nick";
export async function getSessionNickname(matchId: string): Promise<string> {
  try {
    const cached = sessionStorage.getItem(SESSION_NICK_KEY);
    if (cached) return cached;
  } catch {
    /* sessionStorage 불가 환경은 매번 발급 */
  }
  const { nickname } = await http<{ nickname: string }>(
    `/matches/${matchId}/comments/nickname`,
  );
  try {
    sessionStorage.setItem(SESSION_NICK_KEY, nickname);
  } catch {
    /* noop */
  }
  return nickname;
}

// 닉네임 새로 뽑기 — 서버에서 새 닉 받아 세션 캐시 갱신
export async function rerollSessionNickname(matchId: string): Promise<string> {
  const { nickname } = await http<{ nickname: string }>(
    `/matches/${matchId}/comments/nickname`,
  );
  try {
    sessionStorage.setItem(SESSION_NICK_KEY, nickname);
  } catch {
    /* noop */
  }
  return nickname;
}

// 방문 기록 (하루 1기기 1회 집계). 실패는 무시(fire-and-forget).
export function recordVisit(): void {
  void http(`/visit`, {
    method: "POST",
    body: JSON.stringify({ deviceId: getDeviceId() }),
  }).catch(() => {});
}

// ── 비로그인 식별: deviceId (localStorage 영속) ──
const DEVICE_KEY = "tp_device_id";
export function getDeviceId(): string {
  let id = localStorage.getItem(DEVICE_KEY);
  if (!id) {
    id =
      typeof crypto !== "undefined" && crypto.randomUUID
        ? crypto.randomUUID()
        : `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`;
    localStorage.setItem(DEVICE_KEY, id);
  }
  return id;
}

// ── 이메일 기억: 투표 시 입력한 이메일을 자동완성용으로 보관 (최근순 최대 5개) ──
const EMAILS_KEY = "tp_recent_emails";
export function getRecentEmails(): string[] {
  try {
    const raw = localStorage.getItem(EMAILS_KEY);
    return raw ? (JSON.parse(raw) as string[]).filter((e) => typeof e === "string") : [];
  } catch {
    return [];
  }
}
export function rememberEmail(email: string): void {
  const e = email.trim();
  if (!e) return;
  const next = [e, ...getRecentEmails().filter((x) => x.toLowerCase() !== e.toLowerCase())].slice(0, 5);
  try {
    localStorage.setItem(EMAILS_KEY, JSON.stringify(next));
  } catch {
    /* localStorage 불가 환경(시크릿 등)은 조용히 무시 */
  }
}

// 경기별 공유 딥링크
export function matchUrl(matchId: string): string {
  return `${window.location.origin}/match/${matchId}`;
}
