import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import type { Session } from "@supabase/supabase-js";
import { supabase } from "@/integrations/supabase/client";

export interface Profile {
  id: string;
  account_code: string | null;
  telegram_id: string | null;
  telegram_username: string | null;
  display_name: string | null;
  referral_code: string | null;
  balance: number;
}

export interface LedgerEntry {
  id: string;
  type: string;
  amount: number;
  balance_before: number;
  balance_after: number;
  reference_id: string | null;
  description: string | null;
  created_at: string;
}

export interface OrderRow {
  id: string;
  order_code: string;
  package_id: number;
  diamond_amount: number;
  price: number;
  free_fire_uid: string;
  payment_method: string;
  transaction_id: string;
  status: string;
  created_at: string;
}

export interface BonusClaim {
  id: string;
  claim_date: string;
  reward_amount: number;
  created_at: string;
}

export interface ClaimResult {
  claimed: boolean;
  reward?: number;
  balance?: number;
  reason?: string;
}

interface AccountValue {
  ready: boolean;
  session: Session | null;
  profile: Profile | null;
  claimedToday: boolean;
  transactions: LedgerEntry[];
  orders: OrderRow[];
  bonuses: BonusClaim[];
  isAuthed: boolean;
  refresh: () => Promise<void>;
  signUp: (
    email: string,
    password: string,
    fullName?: string,
    referral?: string,
  ) => Promise<string | null>;
  signIn: (email: string, password: string) => Promise<string | null>;
  signOut: () => Promise<void>;
  saveTelegram: (username: string) => Promise<string | null>;
  claimBonus: () => Promise<ClaimResult>;
  recordOrder: (input: {
    orderCode: string;
    packageId: number;
    diamonds: number;
    price: number;
    uid: string;
    paymentMethod: string;
    transactionId: string;
  }) => Promise<void>;
}

const AccountContext = createContext<AccountValue | null>(null);

const db = supabase as unknown as {
  from: (table: string) => any;
  rpc: (fn: string, args?: Record<string, unknown>) => Promise<{ data: unknown; error: unknown }>;
};

export function AccountProvider({ children }: { children: React.ReactNode }) {
  const [ready, setReady] = useState(false);
  const [session, setSession] = useState<Session | null>(null);
  const [profile, setProfile] = useState<Profile | null>(null);
  const [claimedToday, setClaimedToday] = useState(true);
  const [transactions, setTransactions] = useState<LedgerEntry[]>([]);
  const [orders, setOrders] = useState<OrderRow[]>([]);
  const [bonuses, setBonuses] = useState<BonusClaim[]>([]);
  const autoTried = useRef(false);

  const loadData = useCallback(async (uid: string | undefined) => {
    if (!uid) {
      setProfile(null);
      setTransactions([]);
      setOrders([]);
      setBonuses([]);
      setClaimedToday(true);
      return;
    }
    const [p, tx, ord, bon] = await Promise.all([
      db.from("profiles").select("*").eq("id", uid).maybeSingle(),
      db
        .from("balance_transactions")
        .select("*")
        .order("created_at", { ascending: false })
        .limit(100),
      db.from("orders").select("*").order("created_at", { ascending: false }).limit(100),
      db.from("daily_bonus_claims").select("*").order("claim_date", { ascending: false }).limit(60),
    ]);
    setProfile((p.data as Profile | null) ?? null);
    setTransactions((tx.data as LedgerEntry[] | null) ?? []);
    setOrders((ord.data as OrderRow[] | null) ?? []);
    const claims = (bon.data as BonusClaim[] | null) ?? [];
    setBonuses(claims);
    const today = new Date().toISOString().slice(0, 10);
    setClaimedToday(claims.some((c) => c.claim_date === today));
  }, []);

  useEffect(() => {
    let active = true;
    const { data: sub } = supabase.auth.onAuthStateChange((_event, next) => {
      if (!active) return;
      setSession(next);
      void loadData(next?.user.id);
    });

    void (async () => {
      const { data } = await supabase.auth.getSession();
      if (!active) return;
      let current = data.session;
      // Automatic account: every visitor gets a persistent session, no forms.
      if (!current && !autoTried.current) {
        autoTried.current = true;
        const anon = await supabase.auth.signInAnonymously();
        current = anon.data.session ?? null;
      }
      if (!active) return;
      setSession(current);
      await loadData(current?.user.id);
      setReady(true);
    })();

    return () => {
      active = false;
      sub.subscription.unsubscribe();
    };
  }, [loadData]);

  const refresh = useCallback(async () => {
    const { data } = await supabase.auth.getSession();
    await loadData(data.session?.user.id);
  }, [loadData]);

  const applyProfileDetails = useCallback(
    async (uid: string | undefined, fullName?: string, referral?: string) => {
      if (!uid) return;
      const patch: Record<string, string> = {};
      if (fullName && fullName.trim()) patch['display_name'] = fullName.trim();
      if (referral && referral.trim()) patch['referral_code'] = referral.trim().toUpperCase();
      if (Object.keys(patch).length) await db.from("profiles").update(patch).eq("id", uid);
    },
    [],
  );

  const signUp = useCallback(
    async (email: string, password: string, fullName?: string, referral?: string) => {
      const meta = {
        full_name: (fullName ?? "").trim(),
        referral_code: (referral ?? "FF90").trim().toUpperCase() || "FF90",
      };
      // Upgrade the current automatic account so balance/orders carry over.
      const { data, error } = await supabase.auth.updateUser({ email, password, data: meta });
      if (error) {
        const fallback = await supabase.auth.signUp({
          email,
          password,
          options: { emailRedirectTo: window.location.origin, data: meta },
        });
        if (fallback.error) return fallback.error.message;
        if (!fallback.data.session) return "CONFIRM_EMAIL";
        await applyProfileDetails(fallback.data.session.user.id, fullName, referral);
        await refresh();
        return null;
      }
      await applyProfileDetails(data.user?.id, fullName, referral);
      await refresh();
      return null;
    },
    [applyProfileDetails, refresh],
  );

  const signIn = useCallback(async (email: string, password: string) => {
    const { error } = await supabase.auth.signInWithPassword({ email, password });
    return error ? error.message : null;
  }, []);

  const signOut = useCallback(async () => {
    await supabase.auth.signOut();
    autoTried.current = false;
    const anon = await supabase.auth.signInAnonymously();
    setSession(anon.data.session ?? null);
    await loadData(anon.data.session?.user.id);
  }, [loadData]);

  const saveTelegram = useCallback(
    async (username: string) => {
      const { data: sess } = await supabase.auth.getSession();
      const uid = sess.session?.user.id;
      if (!uid) return "NOT_SIGNED_IN";
      const handle = username.trim().replace(/^@/, "");
      const { error } = await db
        .from("profiles")
        .update({ telegram_username: handle, telegram_id: handle.toLowerCase() })
        .eq("id", uid);
      if (error) return (error as { message?: string }).message ?? "ERROR";
      await refresh();
      return null;
    },
    [refresh],
  );

  const claimBonus = useCallback(async (): Promise<ClaimResult> => {
    const { data, error } = await db.rpc("claim_daily_bonus");
    if (error) return { claimed: false, reason: "error" };
    const result = (data ?? {}) as ClaimResult;
    setClaimedToday(true);
    if (typeof result.balance === "number") {
      setProfile((prev) => (prev ? { ...prev, balance: result.balance as number } : prev));
    }
    await refresh();
    return result;
  }, [refresh]);

  const recordOrder = useCallback<AccountValue["recordOrder"]>(
    async (input) => {
      const { data: sess } = await supabase.auth.getSession();
      const uid = sess.session?.user.id;
      if (!uid) return;
      await db.from("orders").insert({
        user_id: uid,
        order_code: input.orderCode,
        package_id: input.packageId,
        diamond_amount: input.diamonds,
        price: input.price,
        free_fire_uid: input.uid,
        payment_method: input.paymentMethod,
        transaction_id: input.transactionId,
        status: "PENDING",
      });
      await refresh();
    },
    [refresh],
  );

  const value = useMemo<AccountValue>(
    () => ({
      ready,
      session,
      profile,
      claimedToday,
      transactions,
      orders,
      bonuses,
      isAuthed: Boolean(session?.user && !session.user.is_anonymous && session.user.email),
      refresh,
      signUp,
      signIn,
      signOut,
      saveTelegram,
      claimBonus,
      recordOrder,
    }),
    [
      ready,
      session,
      profile,
      claimedToday,
      transactions,
      orders,
      bonuses,
      refresh,
      signUp,
      signIn,
      signOut,
      saveTelegram,
      claimBonus,
      recordOrder,
    ],
  );

  return <AccountContext.Provider value={value}>{children}</AccountContext.Provider>;
}

export function useAccount(): AccountValue {
  const ctx = useContext(AccountContext);
  if (!ctx) throw new Error("useAccount must be used inside AccountProvider");
  return ctx;
}
