"use client";

import {
  createContext,
  useContext,
  useEffect,
  useState,
  useCallback,
  type ReactNode,
} from "react";
import { createClient } from "@/lib/supabase/client";
import type { User, Session } from "@supabase/supabase-js";
import type { Profile } from "@/types";

interface AuthContextValue {
  user: User | null;
  session: Session | null;
  profile: Profile | null;
  loading: boolean;
  signUp: (email: string, password: string) => Promise<{ error: string | null }>;
  signIn: (email: string, password: string) => Promise<{ error: string | null }>;
  signInAnonymously: () => Promise<{ error: string | null }>;
  signOut: () => Promise<void>;
  updateProfile: (data: Partial<Profile>) => Promise<{ error: string | null }>;
  refreshProfile: () => Promise<void>;
}

const AuthContext = createContext<AuthContextValue | null>(null);

function mapDbProfile(row: Record<string, unknown>): Profile {
  const loc = row.location as { coordinates?: [number, number] } | null;
  return {
    id: row.id as string,
    username: (row.username as string) ?? null,
    display_name: (row.display_name as string) ?? null,
    age: (row.age as number) ?? null,
    position: (row.position as Profile["position"]) ?? null,
    bio: (row.bio as string) ?? null,
    avatar_url: (row.avatar_url as string) ?? null,
    status: (row.status as Profile["status"]) ?? "offline",
    is_anonymous: (row.is_anonymous as boolean) ?? true,
    kinks: (row.kinks as string[]) ?? [],
    sti_status: (row.sti_status as string) ?? null,
    on_prep: (row.on_prep as boolean) ?? false,
    last_active: (row.last_active as string) ?? new Date().toISOString(),
    lat: loc?.coordinates?.[1] ?? null,
    lng: loc?.coordinates?.[0] ?? null,
    city: (row.city as string) ?? null,
    state: (row.state as string) ?? null,
    id_verified: (row.id_verified as boolean) ?? false,
    id_verified_at: (row.id_verified_at as string) ?? null,
    vanilla_mode: (row.vanilla_mode as boolean) ?? false,
    created_at: (row.created_at as string) ?? new Date().toISOString(),
  };
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const supabase = createClient();
  const [user, setUser] = useState<User | null>(null);
  const [session, setSession] = useState<Session | null>(null);
  const [profile, setProfile] = useState<Profile | null>(null);
  const [loading, setLoading] = useState(true);

  const fetchProfile = useCallback(
    async (userId: string) => {
      const { data, error } = await supabase
        .from("profiles")
        .select("*")
        .eq("id", userId)
        .single();

      if (!error && data) {
        setProfile(mapDbProfile(data));
      }
    },
    [supabase]
  );

  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session: s } }) => {
      setSession(s);
      setUser(s?.user ?? null);
      if (s?.user) fetchProfile(s.user.id);
      setLoading(false);
    });

    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((_event, s) => {
      setSession(s);
      setUser(s?.user ?? null);
      if (s?.user) {
        fetchProfile(s.user.id);
      } else {
        setProfile(null);
      }
    });

    return () => subscription.unsubscribe();
  }, [supabase, fetchProfile]);

  const signUp = async (email: string, password: string) => {
    const { error } = await supabase.auth.signUp({
      email,
      password,
      options: { emailRedirectTo: `${window.location.origin}/profile` },
    });
    return { error: error?.message ?? null };
  };

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

  const signInAnonymously = async () => {
    const { error } = await supabase.auth.signInAnonymously();
    return { error: error?.message ?? null };
  };

  const signOut = async () => {
    await supabase.auth.signOut();
    setProfile(null);
  };

  const updateProfile = async (data: Partial<Profile>) => {
    if (!user) return { error: "Not signed in" };

    const payload: Record<string, unknown> = {
      updated_at: new Date().toISOString(),
      last_active: new Date().toISOString(),
    };

    if (data.display_name !== undefined) payload.display_name = data.display_name;
    if (data.username !== undefined) payload.username = data.username;
    if (data.age !== undefined) payload.age = data.age;
    if (data.position !== undefined) payload.position = data.position;
    if (data.bio !== undefined) payload.bio = data.bio;
    if (data.kinks !== undefined) payload.kinks = data.kinks;
    if (data.sti_status !== undefined) payload.sti_status = data.sti_status;
    if (data.on_prep !== undefined) payload.on_prep = data.on_prep;
    if (data.is_anonymous !== undefined) payload.is_anonymous = data.is_anonymous;
    if (data.status !== undefined) payload.status = data.status;
    if (data.city !== undefined) payload.city = data.city;
    if (data.state !== undefined) payload.state = data.state;
    if (data.id_verified !== undefined) payload.id_verified = data.id_verified;
    if (data.id_verified_at !== undefined) payload.id_verified_at = data.id_verified_at;
    const { error } = await supabase
      .from("profiles")
      .update(payload)
      .eq("id", user.id);

    if (error) return { error: error.message };

    if (data.lat != null && data.lng != null) {
      await supabase.rpc("update_profile_location", {
        p_user_id: user.id,
        p_lat: data.lat,
        p_lng: data.lng,
      });
    }

    await fetchProfile(user.id);
    return { error: null };
  };

  const refreshProfile = async () => {
    if (user) await fetchProfile(user.id);
  };

  return (
    <AuthContext.Provider
      value={{
        user,
        session,
        profile,
        loading,
        signUp,
        signIn,
        signInAnonymously,
        signOut,
        updateProfile,
        refreshProfile,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used within AuthProvider");
  return ctx;
}