// src/lib/stores/auth.svelte.ts
import { browser } from '$app/environment';
import { goto } from '$app/navigation';

export type UserRole = 'unverified_email' | 'verified_email' | 'admin' | 'guest' | 'affiliate';

export interface DecodedToken {
	user_id: string;
	role: UserRole;
	exp: number;
}

export interface User {
	id: string;
	email: string;
	role: UserRole;
	firstName: string;
	lastName: string;
	phone?: string;
	dateOfBirth?: string;
	loyaltyStamps?: number;
	referralCode?: string;
	referralCodeUses?: number;
	referralSavings?: number;
	profilePicUrl?: string;
	previousFirstName?: string;
	previousLastName?: string;
}

class AuthStore {
	private token = $state<string | null>(null);
	private user = $state<User | null>(null);
	private loading = $state(true);

	constructor() {
		if (browser) {
			this.initializeAuth();
			// Check token refresh every 2 minutes
			// (must be shorter than the 5-minute threshold so the
			// refresh check fires before the token actually expires)
			setInterval(
				() => {
					if (this.token) {
						this.refreshTokenIfNeeded();
					}
				},
				2 * 60 * 1000
			);
		}
	}

	get isAuthenticated() {
		return this.token !== null && this.user !== null;
	}

	get currentUser() {
		return this.user;
	}

	get currentToken() {
		return this.token;
	}

	get isLoading() {
		return this.loading;
	}

	get hasLoaded() {
		return !this.loading;
	}

	private initializeAuth() {
		const storedToken = localStorage.getItem('authToken');
		if (storedToken) {
			const decoded = this.decodeToken(storedToken);
			if (decoded && !this.isTokenExpired(decoded)) {
				this.token = storedToken;
				// Set basic user info from token
				this.user = {
					id: decoded.user_id,
					role: decoded.role,
					email: '',
					firstName: '',
					lastName: ''
				};

				// Refresh first so any JTI invalidation from rotation
				// happens before other requests use this token.
				// Then fetch profile with the (potentially refreshed) token.
				this.refreshTokenIfNeeded().then(() => {
					this.fetchUserProfile();
				});
			} else {
				this.clearAuth();
			}
		}
		this.loading = false;
	}

	private decodeToken(token: string): DecodedToken | null {
		try {
			const payload = token.split('.')[1];
			const decoded = JSON.parse(atob(payload));
			return decoded;
		} catch {
			return null;
		}
	}

	private isTokenExpired(decoded: DecodedToken): boolean {
		return decoded.exp * 1000 < Date.now();
	}

	// Simple setters - UI handles the API calls
	setToken(token: string) {
		this.token = token;
		if (browser) {
			localStorage.setItem('authToken', token);
		}

		// Decode to get basic info
		const decoded = this.decodeToken(token);
		if (decoded) {
			this.user = {
				id: decoded.user_id,
				role: decoded.role,
				email: '',
				firstName: '',
				lastName: ''
			};
			this.fetchUserProfile();
		}
	}

	private async fetchUserProfile() {
		if (!this.token) return;

		try {
			const response = await fetch('/api/user/profile', {
				headers: {
					Authorization: `Bearer ${this.token}`
				}
			});

			if (!response.ok) {
				throw new Error('Failed to fetch profile');
			}

			const userData = await response.json();
			this.user = userData;
		} catch {
			this.clearAuth();
		}
	}

	// inside AuthStore
	logout = async () => {
		if (this.token) {
			try {
				await fetch('/api/logout', {
					method: 'POST',
					headers: { Authorization: `Bearer ${this.token}` }
				});
				// eslint-disable-next-line @typescript-eslint/no-unused-vars
			} catch (e) {
				// Ignore network errors - still clear local state
			}
		}
		this.clearAuth();
		// eslint-disable-next-line svelte/no-navigation-without-resolve
		goto('/', { invalidateAll: true });
	};

	private clearAuth() {
		this.token = null;
		this.user = null;
		if (browser) {
			localStorage.removeItem('authToken');
		}
	}

	hasRole(requiredRole: UserRole | UserRole[]): boolean {
		if (!this.user) return false;

		const roles = Array.isArray(requiredRole) ? requiredRole : [requiredRole];
		return roles.includes(this.user.role);
	}

	isAdmin(): boolean {
		return this.hasRole('admin');
	}

	isVerified(): boolean {
		return this.hasRole(['verified_email', 'admin']);
	}

	// Refresh token before it expires
	async refreshTokenIfNeeded() {
		if (!this.token) return;

		const decoded = this.decodeToken(this.token);
		if (!decoded) {
			this.clearAuth();
			return;
		}

		// Refresh if token expires in less than 5 minutes
		// (1-hour token lifetime from backend)
		const fiveMinutes = 5 * 60 * 1000;
		if (decoded.exp * 1000 - Date.now() < fiveMinutes) {
			try {
				const response = await fetch('/api/refresh-token', {
					method: 'POST',
					headers: {
						Authorization: `Bearer ${this.token}`
					}
				});

				if (response.ok) {
					const data = await response.json();
					this.setToken(data.token);
				} else {
					this.clearAuth();
				}
			} catch (error) {
				console.error('Token refresh failed:', error);
			}
		}
	}

	// Manual refresh method
	async refreshProfile() {
		await this.fetchUserProfile();
	}
}

export const authStore = new AuthStore();
