// Path: Frontend/src/context/auth/context.tsx

import { createContext, createSignal, onMount, useContext, type ParentComponent } from "solid-js";

export type AuthProfile = {
	preferred_name: string | null;
	profile_icon_url: string | null;
	headline: string | null;
	bio: string | null;
	timezone: string | null;
	locale: string | null;
	grade_level: string | null;
	learning_goal: string | null;
	created_at: string | null;
	updated_at: string | null;
};

type AuthUser = {
	id: number;
	email: string;
	role: "student" | "teacher";
	full_name: string;
	is_active: boolean;
	created_at?: string;
	updated_at?: string;
	profile: AuthProfile;
};

type AuthResponse = {
	user: AuthUser;
};

type LoginInput = {
	email: string;
	password: string;
	rememberMe: boolean;
};

type SignupInput = {
	firstName: string;
	lastName: string;
	email: string;
	password: string;
};

export type UpdateProfileInput = {
	fullName: string;
	preferredName: string;
	profileIconUrl: string;
	headline: string;
	bio: string;
	timezone: string;
	locale: string;
	gradeLevel: string;
	learningGoal: string;
};

type AuthContextType = {
	user: () => AuthUser | null;
	isReady: () => boolean;
	login: (input: LoginInput) => Promise<AuthUser>;
	signup: (input: SignupInput) => Promise<AuthUser>;
	updateProfile: (input: UpdateProfileInput) => Promise<AuthUser>;
	logout: () => Promise<void>;
	refresh: () => Promise<AuthUser | null>;
};

const AuthContext = createContext<AuthContextType>();

const authRequest = async <T,>(path: string, init?: RequestInit): Promise<T> => {
	const response = await fetch(path, {
		credentials: "include",
		headers: {
			accept: "application/json",
			...(init?.body ? { "content-type": "application/json" } : {}),
			...(init?.headers ?? {}),
		},
		...init,
	});

	if (!response.ok) {
		let message = `Request failed: ${response.status}`;
		try {
			const payload = (await response.json()) as { message?: string };
			if (payload.message) message = payload.message;
		} catch {
			// ignore malformed error bodies
		}

		const error = new Error(message);
		(error as Error & { status?: number }).status = response.status;
		throw error;
	}

	return (await response.json()) as T;
};

export const AuthProvider: ParentComponent = (props) => {
	const [user, setUser] = createSignal<AuthUser | null>(null);
	const [isReady, setIsReady] = createSignal(false);

	const refresh = async () => {
		try {
			const response = await authRequest<AuthResponse>("/api/auth/me");
			setUser(response.user);
			return response.user;
		} catch (error) {
			if ((error as Error & { status?: number }).status === 401) {
				setUser(null);
				return null;
			}

			throw error;
		} finally {
			setIsReady(true);
		}
	};

	const login = async (input: LoginInput) => {
		const response = await authRequest<AuthResponse>("/api/auth/login", {
			method: "POST",
			body: JSON.stringify({
				email: input.email,
				password: input.password,
				remember_me: input.rememberMe,
			}),
		});

		setUser(response.user);
		setIsReady(true);
		return response.user;
	};

	const signup = async (input: SignupInput) => {
		const response = await authRequest<AuthResponse>("/api/auth/register", {
			method: "POST",
			body: JSON.stringify({
				first_name: input.firstName,
				last_name: input.lastName,
				email: input.email,
				password: input.password,
			}),
		});

		setUser(response.user);
		setIsReady(true);
		return response.user;
	};

	const updateProfile = async (input: UpdateProfileInput) => {
		const response = await authRequest<AuthResponse>("/api/auth/me", {
			method: "PATCH",
			body: JSON.stringify({
				full_name: input.fullName,
				preferred_name: input.preferredName,
				profile_icon_url: input.profileIconUrl,
				headline: input.headline,
				bio: input.bio,
				timezone: input.timezone,
				locale: input.locale,
				grade_level: input.gradeLevel,
				learning_goal: input.learningGoal,
			}),
		});

		setUser(response.user);
		setIsReady(true);
		return response.user;
	};

	const logout = async () => {
		await authRequest<{ status: string }>("/api/auth/logout", { method: "POST" });
		setUser(null);
		setIsReady(true);
	};

	onMount(() => {
		void refresh();
	});

	return <AuthContext.Provider value={{ user, isReady, login, signup, updateProfile, logout, refresh }}>{props.children}</AuthContext.Provider>;
};

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

	return context;
};
