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

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

type User = {
    id: string;
    email: string;
    token: string;
    subscribedSubjectIds: string[];
    notificationType: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION';
};

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>;
    updateNotificationType: (type: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION') => 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);
    };

    useEffect(() => {
        setUnauthorizedHandler(() => {
            persist(null);
            Toast.show({
                type: 'info',
                text1: 'Session expired',
                text2: 'Please sign in again.',
                position: 'top',
                visibilityTime: 4000,
            });
        });
        return () => setUnauthorizedHandler(null);
    }, []);

    const updateNotificationType = async (type: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION') => {
        if (!user) return;
        await userApi.updateNotificationType(type, user.token);
        await persist({ ...user, notificationType: type });
    };

    const login = async (payload: LoginPayload) => {
        const res = await authApi.login(payload);
        let subscribedSubjectIds: string[] = [];
        let notificationType: 'PUSH_NOTIFICATION' | 'NO_NOTIFICATION' = 'PUSH_NOTIFICATION';

        if (res.userId) {
            try {
                const dto = await authApi.getUser(res.token);
                subscribedSubjectIds = dto.subjectSet?.map((s) => s.id) ?? [];
                notificationType = dto.notificationType ?? 'PUSH_NOTIFICATION';
            } catch (e) {
                console.error('Failed to load subscriptions on login:', e);
            }
        }

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

    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, updateNotificationType }}>
            {children}
        </AuthContext.Provider>
    );
}

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