import { authLog, authWarn, authError } from './authLogger';

/**
 * Custom storage adapter for Supabase authentication that handles iframe localStorage restrictions.
 * Falls back to sessionStorage or in-memory storage if localStorage is blocked.
 */
class AuthStorage {
  private storage: Storage | null = null;
  private memoryStorage: Map<string, string> = new Map();
  private storageType: 'localStorage' | 'sessionStorage' | 'memory' = 'memory';
  private sessionRecoveryAttempted = false;

  constructor() {
    // Try localStorage first
    try {
      localStorage.setItem('__supabase_test__', 'test');
      localStorage.removeItem('__supabase_test__');
      this.storage = localStorage;
      this.storageType = 'localStorage';
      authLog('[AuthStorage] Using localStorage ✓');
    } catch {
      // Try sessionStorage as fallback
      try {
        sessionStorage.setItem('__supabase_test__', 'test');
        sessionStorage.removeItem('__supabase_test__');
        this.storage = sessionStorage;
        this.storageType = 'sessionStorage';
        authWarn('[AuthStorage] localStorage blocked, using sessionStorage ⚠️');
      } catch {
        // Use in-memory storage as last resort
        this.storageType = 'memory';
        authError('[AuthStorage] Both localStorage and sessionStorage blocked, using in-memory storage ⛔');
        authError('[AuthStorage] Sessions will NOT persist across page reloads!');
        
        // Attempt to recover session from URL
        this.attemptSessionRecoveryFromURL();
      }
    }

    // Listen for storage events to sync across tabs (when possible)
    if (this.storage) {
      window.addEventListener('storage', this.handleStorageChange.bind(this));
    }
  }

  private attemptSessionRecoveryFromURL() {
    if (this.sessionRecoveryAttempted) return;
    this.sessionRecoveryAttempted = true;

    try {
      const urlParams = new URLSearchParams(window.location.hash.substring(1));
      const accessToken = urlParams.get('access_token');
      const refreshToken = urlParams.get('refresh_token');
      
      if (accessToken && refreshToken) {
        authLog('[AuthStorage] Recovering session from URL parameters');
        // Store in memory
        this.memoryStorage.set('sb-auth-token', JSON.stringify({
          access_token: accessToken,
          refresh_token: refreshToken,
          expires_at: Date.now() + 3600000, // 1 hour
        }));
        
        // Clean URL
        window.history.replaceState({}, document.title, window.location.pathname);
      }
    } catch (error: unknown) {
      authError('[AuthStorage] Failed to recover session from URL:', error);
    }
  }

  private handleStorageChange(event: StorageEvent) {
    // Sync auth state across tabs
    if (event.key?.startsWith('sb-') && event.newValue) {
      authLog('[AuthStorage] Syncing auth state across tabs');
    }
  }

  getItem(key: string): string | null {
    authLog('[AuthStorage] Getting key:', key);
    try {
      if (this.storage) {
        const value = this.storage.getItem(key);
        authLog('[AuthStorage] Retrieved from storage:', !!value);
        
        if (value) {
          // Verify it's not expired
          if (key.includes('auth-token')) {
            try {
              const parsed = JSON.parse(value);
              
              // Supabase stores expires_at in seconds, Date.now() is in milliseconds
              // Check if expires_at is in seconds (< year 3000 in milliseconds)
              const expiryTime = parsed.expires_at > 10000000000 
                ? parsed.expires_at  // Already in milliseconds
                : parsed.expires_at * 1000; // Convert from seconds to milliseconds
              
              if (parsed.expires_at && expiryTime < Date.now()) {
                authWarn('[AuthStorage] Token expired, removing', {
                  expires_at: parsed.expires_at,
                  expiryTime: new Date(expiryTime),
                  now: new Date()
                });
                this.removeItem(key);
                return null;
              }
              
              authLog('[AuthStorage] Token valid, expires:', new Date(expiryTime));
            } catch (e) {
              authWarn('[AuthStorage] Could not parse token for expiry check:', e);
            }
          }
        }
        return value;
      }
      authLog('[AuthStorage] Using memory storage');
      return this.memoryStorage.get(key) || null;
    } catch (error: unknown) {
      authError('[AuthStorage] Error reading from storage:', error);
      return this.memoryStorage.get(key) || null;
    }
  }

  setItem(key: string, value: string): void {
    authLog('[AuthStorage] Setting key:', key);
    try {
      if (this.storage) {
        this.storage.setItem(key, value);
      }
      // Always keep in memory as backup
      this.memoryStorage.set(key, value);
    } catch (error: unknown) {
      authError('[AuthStorage] Error writing to storage:', error);
      // Fallback to memory only
      this.memoryStorage.set(key, value);
    }
  }

  removeItem(key: string): void {
    try {
      if (this.storage) {
        this.storage.removeItem(key);
      }
      this.memoryStorage.delete(key);
    } catch (error: unknown) {
      authError('[AuthStorage] Error removing from storage:', error);
      this.memoryStorage.delete(key);
    }
  }

  // Get storage status for diagnostics
  getStorageStatus(): { type: string; persistent: boolean; warning: string | null } {
    return {
      type: this.storageType,
      persistent: this.storageType !== 'memory',
      warning: this.storageType === 'memory' 
        ? 'Sessions will not persist across page reloads. Please enable cookies/storage for this site.'
        : null
    };
  }

  // Clear all auth-related storage (for force logout)
  clearAll(): void {
    authLog('[AuthStorage] Clearing all auth storage');
    try {
      if (this.storage) {
        // Get all keys from storage
        const keys: string[] = [];
        for (let i = 0; i < this.storage.length; i++) {
          const key = this.storage.key(i);
          if (key?.startsWith('sb-')) {
            keys.push(key);
          }
        }
        
        // Remove all Supabase auth keys
        keys.forEach(key => {
          authLog('[AuthStorage] Removing key:', key);
          this.storage!.removeItem(key);
        });
      }
      
      // Clear memory storage
      this.memoryStorage.clear();
      authLog('[AuthStorage] ✓ All auth storage cleared');
    } catch (error: unknown) {
      authError('[AuthStorage] Error clearing storage:', error);
      // Still clear memory storage as fallback
      this.memoryStorage.clear();
    }
  }
}

export const authStorage = new AuthStorage();
