/**
 * Global authentication context for Parcel2Go account linking.
 *
 * Provides:
 * - isLinked: whether user is connected to P2G
 * - isLoading: auth status check in progress
 * - startLogin: redirect to P2G OAuth
 * - logout: disconnect P2G account
 * - error: last error message
 */
import {
	createContext,
	useContext,
	useCallback,
	useEffect,
	useState,
	useMemo,
} from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { getApiErrorMessage } from '../utils';
import { captureException, captureMessage } from '../sentry';

interface AuthContextValue {
	/** True if user is linked to Parcel2Go. */
	isLinked: boolean;
	/** True if auth status check or login is in progress. */
	isLoading: boolean;
	/** Last error message, if any. */
	error: string | null;
	/** Redirect to P2G OAuth login. */
	startLogin: () => void;
	/** Disconnect from P2G account. */
	logout: () => Promise<void>;
	/** Clear error state. */
	clearError: () => void;
}

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

interface AuthProviderProps {
	children: React.ReactNode;
}

export function AuthProvider({ children }: AuthProviderProps) {
	// Compute initial linked state from server-rendered data
	const initialLinked = useMemo(() => {
		const raw =
			typeof window !== 'undefined'
				? window.parcel2goShipping?.authLinked
				: undefined;
		return raw === true || raw === '1' || raw === 1 || raw === 'true';
	}, []);

	const [isLinked, setIsLinked] = useState(initialLinked);
	const [isStatusChecking, setIsStatusChecking] = useState(true);
	const [isLoginInProgress, setIsLoginInProgress] = useState(false);
	const [isLoggingOut, setIsLoggingOut] = useState(false);
	const [error, setError] = useState<string | null>(null);

	// Check auth status on mount
	useEffect(() => {
		let isMounted = true;

		(
			apiFetch({
				path: '/parcel2go-shipping/v1/auth/status',
			}) as Promise<{ linked: boolean }>
		)
			.then((res) => {
				if (isMounted) {
					setIsLinked(Boolean(res?.linked));
				}
			})
			.catch((err: unknown) => {
				captureMessage('Auth status check failed', 'warning', { err });
				// Keep server-rendered value on failure
			})
			.finally(() => {
				if (isMounted) {
					setIsStatusChecking(false);
				}
			});

		return () => {
			isMounted = false;
		};
	}, []);

	const startLogin = useCallback(() => {
		setIsLoginInProgress(true);
		setError(null);

		(
			apiFetch({
				path: '/parcel2go-shipping/v1/auth/authorise',
				method: 'POST',
				data: {},
			}) as Promise<{ authoriseUrl: string }>
		)
			.then(({ authoriseUrl }) => {
				window.location.href = authoriseUrl;
			})
			.catch((e: unknown) => {
				captureException(e instanceof Error ? e : new Error(String(e)));
				setError(
					getApiErrorMessage(
						e,
						'Failed to start Parcel2Go login. Please try again.'
					)
				);
				setIsLoginInProgress(false);
			});
	}, []);

	const logout = useCallback(async () => {
		setIsLoggingOut(true);
		setError(null);
		try {
			await apiFetch({
				path: '/parcel2go-shipping/v1/auth/logout',
				method: 'POST',
				data: {},
			});
			setIsLinked(false);
		} catch (e: unknown) {
			captureException(e instanceof Error ? e : new Error(String(e)));
			setError(
				getApiErrorMessage(e, 'Failed to log out. Please try again.')
			);
		} finally {
			setIsLoggingOut(false);
		}
	}, []);

	const clearError = useCallback(() => {
		setError(null);
	}, []);

	const isLoading = isStatusChecking || isLoginInProgress || isLoggingOut;

	const value = useMemo<AuthContextValue>(
		() => ({
			isLinked,
			isLoading,
			error,
			startLogin,
			logout,
			clearError,
		}),
		[isLinked, isLoading, error, startLogin, logout, clearError]
	);

	return (
		<AuthContext.Provider value={value}>{children}</AuthContext.Provider>
	);
}

/**
 * Access auth context. Must be used within AuthProvider.
 */
export function useParcel2goAuth(): AuthContextValue {
	const context = useContext(AuthContext);
	if (!context) {
		throw new Error('useParcel2goAuth must be used within an AuthProvider');
	}
	return context;
}
