import React, { createContext, useContext, useEffect, useState } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";
import {
    authApi,

    LoginPayload, RegisterPayload, subscriptionsApi, UserUpdateDTO,
} from "@/services/api";

type User = {
    id: string;
    email: string;
    token: string;
    subscribedSubjectIds: string[];
};

type AuthContextValue = {
    user: User | null;
    loading: boolean;
    login: (p: LoginPayload) => Promise<void>;
    register: (p: RegisterPayload) => Promise<void>;
    logout: () => Promise<void>;
    subscribe: (subjectId: string) => Promise<void>;
    unsubscribe: (subjectId: string) => Promise<void>;
    isSubscribed: (subjectId: string) => boolean;
    updateUser: (newEmail?: string, newPassword?: string) => Promise<void>;
};

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

export function AuthProvider({ children }: { children: React.ReactNode }) {
    const [user, setUser] = useState<User | null>(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        AsyncStorage.getItem("auth_user")
            .then((raw) => { if (raw) setUser(JSON.parse(raw)); })
            .finally(() => setLoading(false));
    }, []);

    const persist = async (u: User | null) => {
        if (u) await AsyncStorage.setItem("auth_user", JSON.stringify(u));
        else await AsyncStorage.removeItem("auth_user");
        setUser(u);
    };

    const login = async (payload: LoginPayload) => {
        const res = await authApi.login(payload);

        // Gracefully fetch subscriptions — don't block login if this fails
        let subscribedSubjectIds: string[] = [];
        if (res.userId) {
            try {
                const dto = await authApi.getUser( res.token);
                subscribedSubjectIds = dto.subjectSet?.map((s) => s.id) ?? [];
            } catch {
                // aaaa
            }
        }

        await persist({
            id: res.userId ?? "",
            email: res.email,
            token: res.token,
            subscribedSubjectIds,
        });
    };

    const register = async (payload: RegisterPayload) => {
        await authApi.register(payload);
        await login({
            email: payload.email.trim(),
            password: payload.password.trim(),
        });
    };

    const updateUser = async (newEmail?: string, newPassword?: string) => {
        if (!user) return;
        const body: UserUpdateDTO = {
            email: user.email,
            newEmail: newEmail || undefined,
            password: newPassword || undefined,
            subjectSet: user.subscribedSubjectIds.map((id) => ({ id })),
        };
        const dto = await authApi.updateUser(body, user.token);
        const updated: User = {
            ...user,
            email: newEmail ?? user.email,
            subscribedSubjectIds: dto.subjectSet?.map((s: any) => s.id) ?? user.subscribedSubjectIds,
        };
        await persist(updated);
    };

    const logout = () => persist(null);

    const subscribe = async (subjectId: string) => {
        if (!user) return;
        const dto = await subscriptionsApi.subscribe( subjectId, user.token);
        const updated = {
            ...user,
            subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? [...user.subscribedSubjectIds, subjectId],
        };
        await persist(updated);
    };

    const unsubscribe = async (subjectId: string) => {
        if (!user) return;
        const dto = await subscriptionsApi.unsubscribe( subjectId, user.token);
        const updated = {
            ...user,
            subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? user.subscribedSubjectIds.filter((id) => id !== subjectId),
        };
        await persist(updated);
    };

    const isSubscribed = (subjectId: string) =>
        user?.subscribedSubjectIds.includes(subjectId) ?? false;

    return (
        <AuthContext.Provider value={{ user, loading, login, register, logout, subscribe, unsubscribe, isSubscribed, updateUser }}>
            {children}
        </AuthContext.Provider>
    );
}

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