/**
 * Authentication Context.
 *
 * @package Sideconvo
 */

import {
	createContext,
	useContext,
	useState,
	useEffect,
	ReactNode,
} from '@wordpress/element';

interface AuthContextType {
	isAuthenticated: boolean;
	isLoading: boolean;
	apiKeyExists: boolean;
	saveApiKey: ( key: string ) => Promise< boolean | string >;
	logout: () => void;
	checkAuth: () => Promise< void >;
	/** DEV ONLY: bypass auth gate without an API key */
	devSkipAuth: () => void;
}

const AuthContext = createContext< AuthContextType | undefined >( undefined );

interface AuthProviderProps {
	children: ReactNode;
}

/**
 * Auth Provider component.
 *
 * @param {AuthProviderProps} props Component props.
 * @return {JSX.Element} Provider component.
 */
export function AuthProvider( { children }: AuthProviderProps ) {
	// Initialise immediately from the PHP-localized value — no loading spinner.
	const initialKeyExists = window.sideconvoData?.apiKeyExists || false;
	const [ isAuthenticated, setIsAuthenticated ] = useState( initialKeyExists );
	const [ isLoading, setIsLoading ] = useState( false );
	const [ apiKeyExists, setApiKeyExists ] = useState( initialKeyExists );

	useEffect( () => {
		// Do not poll when unauthenticated — no key to validate, and the user
		// is already on the splash screen. The effect re-runs whenever
		// isAuthenticated changes, so the interval starts automatically when
		// the user connects and stops the moment they disconnect.
		if ( ! isAuthenticated ) {
			return;
		}

		const validateKey = () => {
			// Key found in DB — validate in background; don't block the initial render.
			// PHP uses a 1-hour transient so most calls are served from cache.
			fetch(
				`${ window.sideconvoData.restUrl }sideconvo/v1/auth-status`,
				{
					headers: { 'X-WP-Nonce': window.sideconvoData.nonce },
					cache: 'no-store',
				}
			)
				.then( ( res ) => ( res.ok ? res.json() : Promise.reject( res ) ) )
				.then( ( data ) => {
					// Only update state if Sideconvo explicitly says the key is invalid.
					// Network errors / non-200 responses are ignored to avoid locking
					// users out on transient connectivity issues.
					if ( data.authenticated === false ) {
						setApiKeyExists( false );
						setIsAuthenticated( false );
					} else if ( data.authenticated === true ) {
						setApiKeyExists( true );
						setIsAuthenticated( true );
					}
				} )
				.catch( () => {
					// Network error — be permissive.
				} );
		};

		// Validate immediately on mount, then every 5 minutes.
		validateKey();
		const interval = setInterval( validateKey, 5 * 60 * 1000 );
		return () => clearInterval( interval );
	}, [ isAuthenticated ] ); // eslint-disable-line react-hooks/exhaustive-deps

	/**
	 * Save API key.
	 *
	 * @param {string} key API key.
	 * @return {Promise<boolean|string>} True on success, error message string on failure.
	 */
	const saveApiKey = async ( key: string ): Promise< boolean | string > => {
		try {
			const response = await fetch(
				`${ window.sideconvoData.restUrl }sideconvo/v1/save-api-key`,
				{
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						'X-WP-Nonce': window.sideconvoData.nonce,
					},
					body: JSON.stringify( { api_key: key } ),
				}
			);

			if ( ! response.ok ) {
				const data = await response.json().catch( () => ( {} ) );
				return ( data as { message?: string } ).message ||
					'Invalid API key. Please check and try again.';
			}

			// Clear the cached indexed-count so the sidebar doesn't flash stale
			// data from the previous site after reconnecting.
			localStorage.removeItem( 'sideconvo_indexed_count' );

			// Set the hash before reloading so the HashRouter lands on /sync.
			// A plain reload() is required — changing only the hash via href
			// does not trigger a full reload, so PHP would not re-localize
			// sideconvoData with apiKeyExists: true.
			window.location.hash = '/sync';
			window.location.reload();
			return true;
		} catch ( error ) {
			console.error( 'Error saving API key:', error );
			return 'An error occurred while connecting. Please try again.';
		}
	};

	/**
	 * Logout (clear API key).
	 */
	const logout = () => {
		setApiKeyExists( false );
		setIsAuthenticated( false );
		// API key deletion will be handled by disconnect functionality in Phase 4.
	};

	/**
	 * Check authentication status.
	 * Re-fetches from server to ensure state is current.
	 */
	const checkAuth = async (): Promise< void > => {
		try {
			const response = await fetch(
				`${ window.sideconvoData.restUrl }sideconvo/v1/auth-status`,
				{
					headers: { 'X-WP-Nonce': window.sideconvoData.nonce },
					cache: 'no-store',
				}
			);

			if ( ! response.ok ) {
				return;
			}

			const data = await response.json();
			const authenticated = data.authenticated === true;
			setApiKeyExists( authenticated );
			setIsAuthenticated( authenticated );
		} catch ( error ) {
			console.error( 'Error checking auth status:', error );
			// Network error — don't log the user out.
		}
	};

	/** DEV ONLY: skip auth gate so we can view the app shell without a real API key */
	const devSkipAuth = () => {
		setApiKeyExists( true );
		setIsAuthenticated( true );
	};

	const value = {
		isAuthenticated,
		isLoading,
		apiKeyExists,
		saveApiKey,
		logout,
		checkAuth,
		devSkipAuth,
	};

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

/**
 * Use auth hook.
 *
 * @return {AuthContextType} Auth context.
 */
export function useAuth(): AuthContextType {
	const context = useContext( AuthContext );
	if ( context === undefined ) {
		throw new Error( 'useAuth must be used within AuthProvider' );
	}
	return context;
}
