"use client";

import type { User } from "@supabase/supabase-js";
import { createClient } from "@/lib/supabase/client";
import { isSupabaseConfigured } from "@/lib/supabase/config";
import type { Account, AccountSettings, UserRole } from "@/lib/profile/types";
import {
  exportProfileData,
  putAccount,
  getActiveProfileId,
  putHistoryEntry,
  putFavoriteEntry,
  putAchievementUnlock,
} from "@/lib/profile/db";
import type {
  AchievementUnlock,
  FavoriteEntry,
  PlayHistoryEntry,
} from "@/lib/profile/types";
import { isAdminUsername } from "@/lib/site";
import { setSyncAdapter, LocalOnlySyncAdapter } from "@/lib/adapters/sync";
import { CloudSyncAdapter } from "@/lib/adapters/cloudSync";
import {
  setCompetitiveAdapter,
  LocalCompetitiveAdapter,
} from "@/lib/adapters/competitive";
import { CloudCompetitiveAdapter } from "@/lib/adapters/cloudCompetitive";

export type CloudProfileRow = {
  id: string;
  username: string | null;
  display_name: string;
  avatar_id: string;
  bio: string | null;
  preferred_ui: string;
  needs_ui_setup: boolean;
  competitive_opt_in: boolean;
  competitive_opted_at: string | null;
  competitive_banned: boolean;
  role: UserRole;
  settings: AccountSettings;
  created_at: string;
  updated_at: string;
};

function providerFromUser(user: User): Account["authProvider"] {
  const p = user.app_metadata?.provider as string | undefined;
  if (p === "discord") return p;
  return "oauth";
}

export function cloudProfileToAccount(
  row: CloudProfileRow,
  user: User,
): Account {
  const username = (row.username || "player").toLowerCase();
  return {
    id: row.id,
    username,
    displayName: row.display_name || username,
    avatarId: row.avatar_id || "default",
    bio: row.bio ?? undefined,
    role: isAdminUsername(username) ? "admin" : row.role || "user",
    competitiveOptIn: Boolean(row.competitive_opt_in),
    competitiveOptedAt: row.competitive_opted_at
      ? Date.parse(row.competitive_opted_at)
      : undefined,
    competitiveBanned: Boolean(row.competitive_banned),
    preferredUi: row.preferred_ui || "classic",
    needsUiSetup: Boolean(row.needs_ui_setup),
    settings: row.settings || {},
    createdAt: Date.parse(row.created_at) || Date.now(),
    updatedAt: Date.parse(row.updated_at) || Date.now(),
    authProvider: providerFromUser(user),
    linkedProfileId: getActiveProfileId() ?? undefined,
  };
}

export async function fetchCloudProfile(
  userId: string,
): Promise<CloudProfileRow | null> {
  const supabase = createClient();
  const { data, error } = await supabase
    .from("profiles")
    .select("*")
    .eq("id", userId)
    .maybeSingle();
  if (error) {
    console.warn("[oauth] fetch profile", error.message);
    return null;
  }
  return data as CloudProfileRow | null;
}

/** Ensure a cloud profile exists and mirror it into local IndexedDB. */
export async function ensureLocalMirrorFromCloud(
  user: User,
): Promise<Account | null> {
  if (!isSupabaseConfigured()) return null;

  let row = await fetchCloudProfile(user.id);
  if (!row) {
    // Trigger may lag — insert a row ourselves
    const supabase = createClient();
    const meta = user.user_metadata || {};
    let uname = String(
      meta.preferred_username ||
        meta.user_name ||
        meta.full_name ||
        user.email?.split("@")[0] ||
        "player",
    )
      .toLowerCase()
      .replace(/[^a-z0-9_]+/g, "");
    if (uname.length < 3) uname = `user${user.id.replace(/-/g, "").slice(0, 8)}`;
    const dname = String(meta.full_name || meta.name || uname);
    const { error } = await supabase.from("profiles").upsert({
      id: user.id,
      username: uname,
      display_name: dname,
    });
    if (error) console.warn("[oauth] upsert profile", error.message);
    row = await fetchCloudProfile(user.id);
  }
  if (!row) return null;

  const account = cloudProfileToAccount(row, user);
  await putAccount(account);
  setSyncAdapter(new CloudSyncAdapter());
  setCompetitiveAdapter(new CloudCompetitiveAdapter());
  return account;
}

export async function pushAccountToCloud(account: Account): Promise<void> {
  if (!isSupabaseConfigured()) return;
  if (!account.authProvider || account.authProvider === "local") return;
  const supabase = createClient();
  const { error } = await supabase
    .from("profiles")
    .update({
      display_name: account.displayName,
      avatar_id: account.avatarId,
      bio: account.bio ?? null,
      preferred_ui: account.preferredUi ?? "classic",
      needs_ui_setup: Boolean(account.needsUiSetup),
      competitive_opt_in: account.competitiveOptIn,
      competitive_opted_at: account.competitiveOptedAt
        ? new Date(account.competitiveOptedAt).toISOString()
        : null,
      settings: account.settings ?? {},
      updated_at: new Date().toISOString(),
    })
    .eq("id", account.id);
  if (error) console.warn("[oauth] push account", error.message);
}

const MIGRATE_KEY = "hollowcade_cloud_migrated_";

export function wasCloudMigrated(userId: string): boolean {
  try {
    return localStorage.getItem(MIGRATE_KEY + userId) === "1";
  } catch {
    return true;
  }
}

export function markCloudMigrated(userId: string) {
  try {
    localStorage.setItem(MIGRATE_KEY + userId, "1");
  } catch {
    /* ignore */
  }
}

/** Push local IndexedDB profile metadata into Supabase once. */
export async function migrateLocalProfileToCloud(
  userId: string,
  localProfileId: string,
): Promise<{ ok: boolean; message: string }> {
  if (!isSupabaseConfigured()) {
    return { ok: false, message: "Cloud sync is not configured." };
  }
  const data = await exportProfileData(localProfileId);
  if (!data) {
    return { ok: false, message: "No local profile data to import." };
  }
  const supabase = createClient();

  if (data.playHistory.length) {
    const rows = data.playHistory.map((h) => ({
      user_id: userId,
      game_slug: h.gameSlug,
      sessions: h.sessions,
      total_seconds: h.totalSeconds,
      last_played_at: h.lastPlayedAt
        ? new Date(h.lastPlayedAt).toISOString()
        : null,
    }));
    const { error } = await supabase.from("play_history").upsert(rows);
    if (error) return { ok: false, message: error.message };
  }
  if (data.favorites.length) {
    const rows = data.favorites.map((f) => ({
      user_id: userId,
      game_slug: f.gameSlug,
      favorited_at: new Date(f.favoritedAt).toISOString(),
    }));
    const { error } = await supabase.from("favorites").upsert(rows);
    if (error) return { ok: false, message: error.message };
  }
  if (data.achievements.length) {
    const rows = data.achievements.map((u) => ({
      user_id: userId,
      achievement_id: u.achievementId,
      unlocked_at: new Date(u.unlockedAt).toISOString(),
    }));
    const { error } = await supabase.from("achievements").upsert(rows);
    if (error) return { ok: false, message: error.message };
  }

  markCloudMigrated(userId);
  return { ok: true, message: "Local play data imported to your cloud profile." };
}

/** Pull cloud favorites/history/achievements into the active local profile. */
export async function pullCloudMetadataToLocal(
  userId: string,
  localProfileId: string,
): Promise<void> {
  if (!isSupabaseConfigured()) return;
  const supabase = createClient();

  const { data: hist } = await supabase
    .from("play_history")
    .select("*")
    .eq("user_id", userId);
  for (const h of hist || []) {
    const entry: PlayHistoryEntry = {
      profileId: localProfileId,
      gameSlug: h.game_slug,
      sessions: h.sessions ?? 0,
      totalSeconds: h.total_seconds ?? 0,
      lastPlayedAt: h.last_played_at
        ? Date.parse(h.last_played_at)
        : Date.now(),
    };
    await putHistoryEntry(entry);
  }

  const { data: favs } = await supabase
    .from("favorites")
    .select("*")
    .eq("user_id", userId);
  for (const f of favs || []) {
    const entry: FavoriteEntry = {
      profileId: localProfileId,
      gameSlug: f.game_slug,
      favoritedAt: f.favorited_at ? Date.parse(f.favorited_at) : Date.now(),
    };
    await putFavoriteEntry(entry);
  }

  const { data: unlocks } = await supabase
    .from("achievements")
    .select("*")
    .eq("user_id", userId);
  for (const u of unlocks || []) {
    const entry: AchievementUnlock = {
      profileId: localProfileId,
      achievementId: u.achievement_id,
      unlockedAt: u.unlocked_at ? Date.parse(u.unlocked_at) : Date.now(),
    };
    await putAchievementUnlock(entry);
  }
}

export async function signOutCloud(): Promise<void> {
  if (!isSupabaseConfigured()) return;
  try {
    const supabase = createClient();
    await supabase.auth.signOut();
  } catch {
    /* ignore */
  }
  setSyncAdapter(new LocalOnlySyncAdapter());
  setCompetitiveAdapter(new LocalCompetitiveAdapter());
}
