"use client";

import { LocalCompetitiveAdapter } from "@/lib/adapters/competitive";
import { createClient } from "@/lib/supabase/client";
import { isSupabaseConfigured } from "@/lib/supabase/config";
import { getAccount, getActiveAccountId } from "@/lib/profile/db";
import type { LeaderboardEntry } from "@/lib/profile/types";

/**
 * Dual-write competitive data: local IndexedDB + Supabase when signed in via OAuth.
 */
export class CloudCompetitiveAdapter extends LocalCompetitiveAdapter {
  private async cloudWrite(
    gameSlug: string,
    kind: LeaderboardEntry["kind"],
    value: number,
  ) {
    if (!isSupabaseConfigured()) return;
    try {
      const id = getActiveAccountId();
      if (!id) return;
      const account = await getAccount(id);
      if (
        !account?.competitiveOptIn ||
        account.competitiveBanned ||
        !account.authProvider ||
        account.authProvider === "local"
      ) {
        return;
      }
      const supabase = createClient();
      await supabase.from("leaderboard_entries").upsert(
        {
          user_id: account.id,
          display_name: account.displayName,
          game_slug: gameSlug,
          kind,
          value,
          updated_at: new Date().toISOString(),
        },
        { onConflict: "user_id,game_slug,kind" },
      );
    } catch (e) {
      console.warn("[oauth] leaderboard write", e);
    }
  }

  override async submitScore(gameSlug: string, score: number) {
    await super.submitScore(gameSlug, score);
    if (Number.isFinite(score) && score >= 0 && score <= 1_000_000_000) {
      await this.cloudWrite(gameSlug, "score", Math.floor(score));
    }
  }

  override async submitPlayTime(gameSlug: string, seconds: number) {
    await super.submitPlayTime(gameSlug, seconds);
    const id = getActiveAccountId();
    if (!id) return;
    const account = await getAccount(id);
    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 this.cloudWrite(gameSlug, "play_time", total);
  }

  override async unlockAchievement(achievementId: string) {
    await super.unlockAchievement(achievementId);
    // Value recomputed in parent via leaderboard upsert — mirror global row if any
    const id = getActiveAccountId();
    if (!id) return;
    const { getLeaderboard } = await import("@/lib/profile/db");
    const rows = await getLeaderboard("_global", "achievements");
    const mine = rows.find((r) => r.accountId === id);
    if (mine) {
      await this.cloudWrite("_global", "achievements", mine.value);
    }
  }

  override async getLeaderboard(
    gameSlug: string,
    kind: LeaderboardEntry["kind"] = "play_time",
  ) {
    const local = await super.getLeaderboard(gameSlug, kind);
    if (!isSupabaseConfigured()) return local;
    try {
      const supabase = createClient();
      const { data } = await supabase
        .from("leaderboard_entries")
        .select("*")
        .eq("game_slug", gameSlug)
        .eq("kind", kind)
        .order("value", { ascending: false })
        .limit(50);
      if (!data?.length) return local;
      const cloud: LeaderboardEntry[] = data.map((r) => ({
        id: r.id,
        accountId: r.user_id,
        displayName: r.display_name,
        gameSlug: r.game_slug,
        kind: r.kind as LeaderboardEntry["kind"],
        value: Number(r.value),
        updatedAt: Date.parse(r.updated_at) || Date.now(),
      }));
      // Prefer cloud when present; merge unique by accountId
      const byId = new Map<string, LeaderboardEntry>();
      for (const e of local) byId.set(e.accountId, e);
      for (const e of cloud) byId.set(e.accountId, e);
      return [...byId.values()].sort((a, b) => b.value - a.value);
    } catch {
      return local;
    }
  }
}
