import { 
  signInWithEmailAndPassword, 
  createUserWithEmailAndPassword,
  signOut,
  onAuthStateChanged,
  User as FirebaseUser,
  getIdToken
} from 'firebase/auth';
import axios from 'axios';
import { auth } from '../config/firebase';
import { LoginCredentials, AuthResult, User } from '../types/auth';

class AuthService {
  private currentUser: FirebaseUser | null = null;
  private authStateListeners: Array<(user: FirebaseUser | null) => void> = [];
  private tokenRefreshInterval: NodeJS.Timeout | null = null;
  private isRefreshing = false;

  constructor() {
    // Listen for auth state changes
    onAuthStateChanged(auth, (user) => {
      this.currentUser = user;
      this.updateAxiosHeaders(user);
      // Notify all listeners
      this.authStateListeners.forEach(listener => listener(user));
      
      // Clear existing interval and set up new one
      if (this.tokenRefreshInterval) {
        clearInterval(this.tokenRefreshInterval);
      }
      
      if (user) {
        // Set up periodic token refresh (every 45 minutes to be safe)
        this.tokenRefreshInterval = setInterval(async () => {
          if (this.currentUser && !this.isRefreshing) {
            try {
              this.isRefreshing = true;
              await this.updateAxiosHeaders(this.currentUser);
            } catch (error) {
              console.error('Periodic token refresh failed:', error);
              // Don't logout on refresh failure, let the next request handle it
            } finally {
              this.isRefreshing = false;
            }
          }
        }, 45 * 60 * 1000); // 45 minutes
      }
    });
  }

  private async updateAxiosHeaders(user: FirebaseUser | null) {
    if (user) {
      try {
        // Force token refresh to ensure we have a fresh token
        const token = await getIdToken(user, true);
        axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
      } catch (error) {
        console.error('Failed to get ID token:', error);
        delete axios.defaults.headers.common['Authorization'];
      }
    } else {
      delete axios.defaults.headers.common['Authorization'];
    }
  }

  onAuthStateChanged(callback: (user: FirebaseUser | null) => void) {
    this.authStateListeners.push(callback);
    return () => {
      this.authStateListeners = this.authStateListeners.filter(
        listener => listener !== callback
      );
    };
  }

  async login(credentials: LoginCredentials): Promise<AuthResult> {
    try {
      const userCredential = await signInWithEmailAndPassword(
        auth, 
        credentials.email, 
        credentials.password
      );
      
      const user = userCredential.user;
      const token = await getIdToken(user);
      
      return {
        user: {
          id: user.uid,
          email: user.email!,
          name: user.displayName || user.email!.split('@')[0]
        },
        token,
        refreshToken: user.refreshToken,
        expiresIn: 3600 // Firebase tokens typically expire in 1 hour
      };
    } catch (error: any) {
      throw new Error(error.message || 'Login failed');
    }
  }

  async register(credentials: LoginCredentials & { name?: string }): Promise<AuthResult> {
    try {
      const userCredential = await createUserWithEmailAndPassword(
        auth,
        credentials.email,
        credentials.password
      );
      
      const user = userCredential.user;
      const token = await getIdToken(user);
      
      return {
        user: {
          id: user.uid,
          email: user.email!,
          name: credentials.name || user.email!.split('@')[0]
        },
        token,
        refreshToken: user.refreshToken,
        expiresIn: 3600
      };
    } catch (error: any) {
      throw new Error(error.message || 'Registration failed');
    }
  }

  async logout(): Promise<void> {
    try {
      if (this.tokenRefreshInterval) {
        clearInterval(this.tokenRefreshInterval);
        this.tokenRefreshInterval = null;
      }
      await signOut(auth);
    } catch (error) {
      console.error('Logout failed:', error);
      throw new Error('Logout failed');
    }
  }

  async validateToken(): Promise<User | null> {
    if (!this.currentUser) {
      return null;
    }

    try {
      // Firebase handles token validation automatically
      // Just return the current user info
      return {
        id: this.currentUser.uid,
        email: this.currentUser.email!,
        name: this.currentUser.displayName || this.currentUser.email!.split('@')[0]
      };
    } catch (error) {
      return null;
    }
  }

  getCurrentUser(): User | null {
    if (!this.currentUser) {
      return null;
    }

    return {
      id: this.currentUser.uid,
      email: this.currentUser.email!,
      name: this.currentUser.displayName || this.currentUser.email!.split('@')[0]
    };
  }

  async getToken(): Promise<string | null> {
    if (!this.currentUser) {
      return null;
    }

    try {
      // Only force refresh if we're not already refreshing
      if (!this.isRefreshing) {
        this.isRefreshing = true;
        try {
          const token = await getIdToken(this.currentUser, true);
          this.isRefreshing = false;
          return token;
        } catch (error) {
          this.isRefreshing = false;
          throw error;
        }
      } else {
        // If already refreshing, just get the current token
        return await getIdToken(this.currentUser, false);
      }
    } catch (error) {
      console.error('Failed to get ID token:', error);
      return null;
    }
  }

  isAuthenticated(): boolean {
    return !!this.currentUser;
  }

  // Cleanup method
  destroy() {
    if (this.tokenRefreshInterval) {
      clearInterval(this.tokenRefreshInterval);
    }
  }
}

export const authService = new AuthService();