import { useState, useEffect, useCallback } from 'react';
import pb from '../lib/pocketbase';
import { trackEvent } from '../lib/analytics';

export interface AuthUser {
  id: string;
  email: string;
  isAdmin: boolean;
  subscription: string;
  newsletter: boolean;
  canSeeListings: boolean;
}

function recordToUser(record: { id: string; [key: string]: unknown }): AuthUser {
  if (typeof record.email !== 'string') {
    throw new Error('PocketBase record missing email field');
  }
  return {
    id: record.id,
    email: record.email,
    isAdmin: typeof record.is_admin === 'boolean' ? record.is_admin : false,
    subscription: typeof record.subscription === 'string' ? record.subscription : 'free',
    newsletter: typeof record.newsletter === 'boolean' ? record.newsletter : false,
    canSeeListings: typeof record.can_see_listings === 'boolean' ? record.can_see_listings : false,
  };
}

function authRefreshInvalidated(error: unknown): boolean {
  const status = (error as { status?: unknown })?.status;
  return status === 401 || status === 403;
}

export function useAuth() {
  const [user, setUser] = useState<AuthUser | null>(() => {
    if (pb.authStore.isValid && pb.authStore.record) {
      return recordToUser(pb.authStore.record);
    }
    return null;
  });
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Sync with authStore changes (cross-tab, external updates)
  useEffect(() => {
    const unsubscribe = pb.authStore.onChange(() => {
      if (pb.authStore.isValid && pb.authStore.record) {
        setUser(recordToUser(pb.authStore.record));
      } else {
        setUser(null);
      }
    });
    return unsubscribe;
  }, []);

  const login = useCallback(async (email: string, password: string) => {
    setLoading(true);
    setError(null);
    try {
      const result = await pb.collection('users').authWithPassword(email, password);
      setUser(recordToUser(result.record));
      trackEvent('Login', { method: 'email' });
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Login failed';
      setError(msg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

  const register = useCallback(async (email: string, password: string) => {
    setLoading(true);
    setError(null);
    try {
      await pb.collection('users').create({
        email,
        password,
        passwordConfirm: password,
        newsletter: true,
      });
      // Auto-login after registration
      const result = await pb.collection('users').authWithPassword(email, password);
      setUser(recordToUser(result.record));
      trackEvent('Register');
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Registration failed';
      setError(msg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

  const loginWithOAuth = useCallback(async (provider: string) => {
    setLoading(true);
    setError(null);
    try {
      const result = await pb.collection('users').authWithOAuth2({
        provider,
        createData: { newsletter: true },
      });
      setUser(recordToUser(result.record));
      trackEvent('Login', { method: provider });
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'OAuth login failed';
      setError(msg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

  const logout = useCallback(() => {
    trackEvent('Logout');
    pb.authStore.clear();
    setUser(null);
  }, []);

  const requestPasswordReset = useCallback(async (email: string) => {
    setLoading(true);
    setError(null);
    try {
      await pb.collection('users').requestPasswordReset(email);
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Password reset request failed';
      setError(msg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

  const refreshAuth = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const result = await pb.collection('users').authRefresh();
      const refreshedUser = recordToUser(result.record);
      setUser(refreshedUser);
      return refreshedUser;
    } catch (err) {
      // Only clear auth on explicit token rejection. Network and 5xx failures
      // should not log users out during background refresh.
      if (authRefreshInvalidated(err)) {
        pb.authStore.clear();
        setUser(null);
      }
      throw err;
    } finally {
      setLoading(false);
    }
  }, []);

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

  return {
    user,
    loading,
    error,
    login,
    register,
    loginWithOAuth,
    logout,
    requestPasswordReset,
    refreshAuth,
    clearError,
  };
}
