import { createClient } from '@supabase/supabase-js';
import { getWebSupabaseConfig } from '../../../shared/supabase-config.js';
import { getRuntimeEnvironment } from '../../../shared/runtime.js';

const supabaseConfig = getWebSupabaseConfig();
const runtime = getRuntimeEnvironment('web');
const AUTH_STORAGE_PREFIX = 'invttrdg_web';
const ACCESS_TOKEN_KEY = `${AUTH_STORAGE_PREFIX}_access_token`;
const REFRESH_TOKEN_KEY = `${AUTH_STORAGE_PREFIX}_refresh_token`;
const USER_KEY = `${AUTH_STORAGE_PREFIX}_auth_user`;
const authListeners = new Set<(event: string, session: any) => void>();

type PlatformSession = {
    access_token: string;
    refresh_token: string;
    user: {
        id: string;
        email?: string;
        role?: string;
        plan?: string;
        display_name?: string;
        user_metadata?: Record<string, unknown>;
    };
};

class PlatformAuthError extends Error {
    status?: number;

    constructor(message: string, status?: number) {
        super(message);
        this.name = 'PlatformAuthError';
        this.status = status;
    }
}

if (!supabaseConfig.isConfigured) {
    console.warn('Missing Supabase environment variables for legacy data client fallback');
}

const dataClient = supabaseConfig.isConfigured
    ? createClient(supabaseConfig.url, supabaseConfig.anonKey)
    : null;

function parseJson<T>(value: string | null): T | null {
    if (!value) return null;
    try {
        return JSON.parse(value) as T;
    } catch {
        return null;
    }
}

function getStoredSession(): PlatformSession | null {
    if (typeof window === 'undefined') return null;
    const accessToken = window.localStorage.getItem(ACCESS_TOKEN_KEY);
    const refreshToken = window.localStorage.getItem(REFRESH_TOKEN_KEY);
    const user = parseJson<PlatformSession['user']>(window.localStorage.getItem(USER_KEY));
    if (!accessToken || !refreshToken || !user?.id) {
        return null;
    }
    return {
        access_token: accessToken,
        refresh_token: refreshToken,
        user,
    };
}

function saveSession(session: PlatformSession): void {
    window.localStorage.setItem(ACCESS_TOKEN_KEY, session.access_token);
    window.localStorage.setItem(REFRESH_TOKEN_KEY, session.refresh_token);
    window.localStorage.setItem(USER_KEY, JSON.stringify(session.user));
}

function clearSession(): void {
    window.localStorage.removeItem(ACCESS_TOKEN_KEY);
    window.localStorage.removeItem(REFRESH_TOKEN_KEY);
    window.localStorage.removeItem(USER_KEY);
}

function emitAuthChange(event: string, session: PlatformSession | null): void {
    for (const listener of authListeners) {
        listener(event, session);
    }
}

function decodeJwtPayload(token: string): Record<string, any> | null {
    try {
        const [, payload] = token.split('.');
        if (!payload) return null;
        return JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/')));
    } catch {
        return null;
    }
}

function isAccessTokenFresh(token: string): boolean {
    const claims = decodeJwtPayload(token);
    const exp = Number(claims?.exp || 0);
    if (!exp) return false;
    return exp > Math.floor(Date.now() / 1000) + 60;
}

function normalizeUser(input: any): PlatformSession['user'] {
    return {
        id: String(input?.id || input?.sub || '').trim(),
        email: typeof input?.email === 'string' ? input.email : undefined,
        role: typeof input?.role === 'string' ? input.role : undefined,
        plan: typeof input?.plan === 'string' ? input.plan : undefined,
        display_name: typeof input?.displayName === 'string' ? input.displayName : undefined,
        user_metadata: {
            role: input?.role,
            plan: input?.plan,
            displayName: input?.displayName,
        },
    };
}

async function platformRequest<T>(
    path: string,
    options?: {
        method?: string;
        accessToken?: string;
        body?: Record<string, unknown>;
    }
): Promise<T> {
    const response = await fetch(`${runtime.platformApiUrl}${path}`, {
        method: options?.method || 'GET',
        headers: {
            'Content-Type': 'application/json',
            'x-product-id': runtime.productId,
            ...(options?.accessToken ? { Authorization: `Bearer ${options.accessToken}` } : {}),
        },
        body: options?.body ? JSON.stringify(options.body) : undefined,
    });

    const payload = await response.json().catch(() => ({}));
    if (!response.ok) {
        throw new PlatformAuthError(
            String((payload as { message?: string; error?: string }).message || (payload as { error?: string }).error || `HTTP ${response.status}`),
            response.status
        );
    }

    return payload as T;
}

async function getPlatformUser(accessToken: string): Promise<PlatformSession['user']> {
    const me = await platformRequest<any>('/auth/me', { accessToken });
    return normalizeUser(me);
}

async function refreshPlatformSession(refreshToken: string): Promise<PlatformSession> {
    const refreshed = await platformRequest<{ accessToken: string; refreshToken: string }>('/auth/refresh', {
        method: 'POST',
        body: { refreshToken },
    });
    const user = await getPlatformUser(refreshed.accessToken);
    const nextSession: PlatformSession = {
        access_token: refreshed.accessToken,
        refresh_token: refreshed.refreshToken,
        user,
    };
    saveSession(nextSession);
    return nextSession;
}

async function ensurePlatformSession(): Promise<PlatformSession | null> {
    const stored = getStoredSession();
    if (!stored) {
        return null;
    }

    if (isAccessTokenFresh(stored.access_token) && stored.user?.id) {
        return stored;
    }

    try {
        const user = await getPlatformUser(stored.access_token);
        const nextSession = { ...stored, user };
        saveSession(nextSession);
        return nextSession;
    } catch (error) {
        if ((error as PlatformAuthError)?.status === 401 || (error as PlatformAuthError)?.status === 403) {
            try {
                const refreshed = await refreshPlatformSession(stored.refresh_token);
                emitAuthChange('TOKEN_REFRESHED', refreshed);
                return refreshed;
            } catch {
                clearSession();
                emitAuthChange('SIGNED_OUT', null);
                return null;
            }
        }
        throw error;
    }
}

function getPasswordResetToken(): string | null {
    if (typeof window === 'undefined') return null;
    const url = new URL(window.location.href);
    const directToken = url.searchParams.get('token');
    if (directToken) return directToken;

    const hashParams = new URLSearchParams(url.hash.replace(/^#/, ''));
    return hashParams.get('token');
}

const auth = {
    async getSession() {
        return { data: { session: await ensurePlatformSession() } };
    },

    onAuthStateChange(callback: (event: string, session: PlatformSession | null) => void) {
        authListeners.add(callback);
        return {
            data: {
                subscription: {
                    unsubscribe() {
                        authListeners.delete(callback);
                    }
                }
            }
        };
    },

    async signInWithPassword({ email, password }: { email: string; password: string; }) {
        try {
            const response = await platformRequest<{
                accessToken: string;
                refreshToken: string;
                user: unknown;
            }>('/auth/login', {
                method: 'POST',
                body: {
                    email,
                    password,
                    productId: runtime.productId,
                },
            });

            const session: PlatformSession = {
                access_token: response.accessToken,
                refresh_token: response.refreshToken,
                user: normalizeUser(response.user),
            };
            saveSession(session);
            emitAuthChange('SIGNED_IN', session);
            return { data: { session }, error: null };
        } catch (error) {
            return { data: { session: null }, error };
        }
    },

    async signUp({ email, password }: { email: string; password: string; }) {
        try {
            const response = await platformRequest<{
                accessToken: string;
                refreshToken: string;
                user: unknown;
            }>('/auth/register', {
                method: 'POST',
                body: {
                    email,
                    password,
                    displayName: email.split('@')[0],
                    productId: runtime.productId,
                },
            });

            const session: PlatformSession = {
                access_token: response.accessToken,
                refresh_token: response.refreshToken,
                user: normalizeUser(response.user),
            };
            saveSession(session);
            emitAuthChange('SIGNED_IN', session);
            return { data: { session }, error: null };
        } catch (error) {
            return { data: { session: null }, error };
        }
    },

    async signOut() {
        clearSession();
        emitAuthChange('SIGNED_OUT', null);
        return { error: null };
    },

    async resetPasswordForEmail(email: string, _options?: { redirectTo?: string; }) {
        try {
            void _options;
            await platformRequest('/auth/forgot-password', {
                method: 'POST',
                body: {
                    email,
                    productId: runtime.productId,
                },
            });
            return { data: {}, error: null };
        } catch (error) {
            return { data: {}, error };
        }
    },

    async updateUser({ password }: { password: string; }) {
        try {
            const token = getPasswordResetToken();
            if (!token) {
                throw new PlatformAuthError('Missing password reset token');
            }
            await platformRequest('/auth/reset-password', {
                method: 'POST',
                body: {
                    token,
                    newPassword: password,
                },
            });
            return { data: {}, error: null };
        } catch (error) {
            return { data: {}, error };
        }
    },
};

export const supabase = {
    from: (...args: any[]) => {
        if (!dataClient) {
            throw new Error('Legacy Supabase data client is not configured');
        }
        return (dataClient.from as any)(...args);
    },
    auth,
};
