"use client";

import {
  addAnalyticsEvent,
  getAccount,
  getActiveAccountId,
  getGlobalLeaderboard,
  getLeaderboard,
  getUnlocks,
  upsertLeaderboard,
} from "@/lib/profile/db";
import type { LeaderboardEntry } from "@/lib/profile/types";
import { getAchievementDef } from "@/lib/profile/achievements";

export interface CompetitiveAdapter {
  isEnrolled(): Promise<boolean>;
  submitScore(
    gameSlug: string,
    score: number,
    meta?: Record<string, unknown>,
  ): Promise<void>;
  submitPlayTime(gameSlug: string, seconds: number): Promise<void>;
  unlockAchievement(achievementId: string): Promise<void>;
  getLeaderboard(
    gameSlug: string,
    kind?: LeaderboardEntry["kind"],
  ): Promise<LeaderboardEntry[]>;
  getGlobalLeaderboard(
    kind?: LeaderboardEntry["kind"],
  ): Promise<LeaderboardEntry[]>;
}

/** Local competitive store: only enrolled, non-banned accounts publish. */
export class LocalCompetitiveAdapter implements CompetitiveAdapter {
  async isEnrolled(): Promise<boolean> {
    const id = getActiveAccountId();
    if (!id) return false;
    const account = await getAccount(id);
    return Boolean(
      account?.competitiveOptIn && !account.competitiveBanned,
    );
  }

  private async enrolledAccount() {
    const id = getActiveAccountId();
    if (!id) return null;
    const account = await getAccount(id);
    if (!account?.competitiveOptIn || account.competitiveBanned) return null;
    return account;
  }

  async submitScore(gameSlug: string, score: number) {
    const account = await this.enrolledAccount();
    if (!account || !Number.isFinite(score) || score < 0) return;
    // Basic sanity: discard absurd values
    if (score > 1_000_000_000) return;
    await upsertLeaderboard({
      accountId: account.id,
      displayName: account.displayName,
      gameSlug,
      kind: "score",
      value: Math.floor(score),
    });
    await addAnalyticsEvent({
      type: "score",
      accountId: account.id,
      gameSlug,
      value: Math.floor(score),
      at: Date.now(),
    });
  }

  async submitPlayTime(gameSlug: string, seconds: number) {
    const account = await this.enrolledAccount();
    if (!account || seconds <= 0) return;
    // Prefer linked profile totals when available
    let total = seconds;
    if (account.linkedProfileId) {
      const { getHistoryEntry } = await import("@/lib/profile/db");
      const hist = await getHistoryEntry(account.linkedProfileId, gameSlug);
      if (hist) total = hist.totalSeconds;
    }
    await upsertLeaderboard({
      accountId: account.id,
      displayName: account.displayName,
      gameSlug,
      kind: "play_time",
      value: total,
    });
    await addAnalyticsEvent({
      type: "session_end",
      accountId: account.id,
      profileId: account.linkedProfileId,
      gameSlug,
      value: seconds,
      at: Date.now(),
    });
  }

  async unlockAchievement(achievementId: string) {
    const account = await this.enrolledAccount();
    if (!account) return;
    const def = getAchievementDef(achievementId);
    const points = def?.points ?? 0;
    const unlocks = account.linkedProfileId
      ? await getUnlocks(account.linkedProfileId)
      : [];
    const totalPoints = unlocks.reduce((sum, u) => {
      const d = getAchievementDef(u.achievementId);
      return sum + (d?.points ?? 0);
    }, 0);
    await upsertLeaderboard({
      accountId: account.id,
      displayName: account.displayName,
      gameSlug: def?.gameSlug ?? "_global",
      kind: "achievements",
      value: Math.max(totalPoints, points),
    });
    await addAnalyticsEvent({
      type: "achievement",
      accountId: account.id,
      profileId: account.linkedProfileId,
      value: points,
      at: Date.now(),
    });
  }

  async getLeaderboard(
    gameSlug: string,
    kind: LeaderboardEntry["kind"] = "play_time",
  ) {
    return getLeaderboard(gameSlug, kind);
  }

  async getGlobalLeaderboard(
    kind: LeaderboardEntry["kind"] = "play_time",
  ) {
    return getGlobalLeaderboard(kind);
  }
}

let competitiveAdapter: CompetitiveAdapter = new LocalCompetitiveAdapter();

export function getCompetitiveAdapter() {
  return competitiveAdapter;
}

export function setCompetitiveAdapter(adapter: CompetitiveAdapter) {
  competitiveAdapter = adapter;
}
