/**
 * Token Management Utilities
 * Handles token storage, retrieval, and refresh operations
 */

const ACCESS_TOKEN_KEY = 'accessToken';
const REFRESH_TOKEN_KEY = 'refreshToken';
const ID_TOKEN_KEY = 'idToken';
const USER_DATA_KEY = 'userData';

// Check if running in production mode
const isProduction = (): boolean => {
  return import.meta.env.PROD || import.meta.env.MODE === 'production';
};

/**
 * Cookie utility functions
 */
export const cookieUtils = {
  /**
   * Set a cookie with the given name, value, and options
   */
  set(name: string, value: string, days: number = 7): void {
    const expires = new Date();
    expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
    const cookieValue = `${name}=${encodeURIComponent(value)}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;
    document.cookie = cookieValue;
  },

  /**
   * Get a cookie by name
   */
  get(name: string): string | null {
    const nameEQ = name + '=';
    const cookies = document.cookie.split(';');
    for (let i = 0; i < cookies.length; i++) {
      let cookie = cookies[i];
      if (!cookie) continue;
      while (cookie.charAt(0) === ' ') cookie = cookie.substring(1, cookie.length);
      if (cookie.indexOf(nameEQ) === 0) {
        return decodeURIComponent(cookie.substring(nameEQ.length, cookie.length));
      }
    }
    return null;
  },

  /**
   * Remove a cookie
   */
  remove(name: string): void {
    document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
  },

  /**
   * Clear all authentication cookies
   * Attempts to clear cookies with different paths and domains
   */
  clearAll(): void {
    const cookieNames = [ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY, ID_TOKEN_KEY, USER_DATA_KEY];

    cookieNames.forEach(name => {
      // Remove with default path
      this.remove(name);

      // Remove with root path explicitly
      document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;

      // Remove with domain (if applicable)
      const hostname = window.location.hostname;
      if (hostname !== 'localhost' && hostname !== '127.0.0.1') {
        document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${hostname};`;
        document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.${hostname};`;
      }
    });
  },
};


export class TokenManager {
  /**
   * Store access token
   */
  static setAccessToken(token: string): void {

    if (isProduction()) {
      return; // No-op - rely on httpOnly cookies
    }

    // Dev only: Store for debugging and cross-port requests
    localStorage.setItem(ACCESS_TOKEN_KEY, token);
  }

  /**
   * Get access token
   * 
   */
  static getAccessToken(): string | null {

    if (isProduction()) {
      return null;
    }

    // Dev: Return from localStorage
    return localStorage.getItem(ACCESS_TOKEN_KEY);
  }

  /**
   * Store refresh token
   */
  static setRefreshToken(token: string): void {
    // SECURITY: In production, don't store tokens client-side
    if (isProduction()) {
      return; // No-op - rely on httpOnly cookies
    }

    // Dev only
    localStorage.setItem(REFRESH_TOKEN_KEY, token);
  }

  /**
   * Get refresh token
   */
  static getRefreshToken(): string | null {
    // SECURITY: In production, return null - backend reads from cookie
    if (isProduction()) {
      return null;
    }

    return localStorage.getItem(REFRESH_TOKEN_KEY);
  }

  static setIdToken(token: string): void {
    // ID token is needed for Okta logout, use sessionStorage (more secure than localStorage)
    sessionStorage.setItem(ID_TOKEN_KEY, token);
  }

  /**
   * Get ID token
   */
  static getIdToken(): string | null {
    return sessionStorage.getItem(ID_TOKEN_KEY);
  }

  /**
   * Store user data (not sensitive - can be stored in localStorage)
   */
  static setUserData(user: any): void {
    localStorage.setItem(USER_DATA_KEY, JSON.stringify(user));
  }

  /**
   * Get user data
   */
  static getUserData(): any | null {
    const data = localStorage.getItem(USER_DATA_KEY);
    if (!data) return null;
    try {
      return JSON.parse(data);
    } catch {
      return null;
    }
  }


  static clearAll(): void {
    //: Set logout flag in sessionStorage FIRST (before clearing)
    // This flag survives the redirect and prevents auto-authentication
    try {
      sessionStorage.setItem('__logout_in_progress__', 'true');
      sessionStorage.setItem('__force_logout__', 'true');
    } catch (e) {
      console.warn('Could not set logout flags:', e);
    }

    // Clear user data (stored in both modes)
    try {
      localStorage.removeItem(USER_DATA_KEY);
      sessionStorage.removeItem(ID_TOKEN_KEY);
    } catch (e) {
      console.warn('Error clearing user data:', e);
    }

    // In production, httpOnly cookies are cleared by backend
    // Only need to clear user data above
    if (isProduction()) {
      // Restore logout flags after clearing
      try {
        sessionStorage.setItem('__logout_in_progress__', 'true');
        sessionStorage.setItem('__force_logout__', 'true');
      } catch (e) {
        // Ignore
      }
      return;
    }

    // Dev MODE: Clear everything
    const authKeys = [
      ACCESS_TOKEN_KEY,
      REFRESH_TOKEN_KEY,
      ID_TOKEN_KEY,
      USER_DATA_KEY,
      'oktaToken',
      'authToken',
      'user',
      'authState',
      'access_token',
      'refresh_token',
      'id_token',
      'token',
      'auth',
      'authentication',
      'persist:root',
      'persist:auth',
      'redux-persist',
    ];

    authKeys.forEach(key => {
      try {
        localStorage.removeItem(key);
        sessionStorage.removeItem(key);
      } catch (e) {
        console.warn(`Error removing ${key}:`, e);
      }
    });

    // Clear ALL localStorage
    try {
      localStorage.clear();
    } catch (e) {
      console.error('Error clearing localStorage:', e);
    }

    // Clear ALL sessionStorage except logout flags
    try {
      const keysToKeep = ['__logout_in_progress__', '__force_logout__'];
      const allKeys: string[] = [];
      for (let i = 0; i < sessionStorage.length; i++) {
        const key = sessionStorage.key(i);
        if (key && !keysToKeep.includes(key)) {
          allKeys.push(key);
        }
      }
      allKeys.forEach(key => sessionStorage.removeItem(key));
    } catch (e) {
      console.error('Error clearing sessionStorage:', e);
    }

    // Clear client-side cookies (development only)
    cookieUtils.clearAll();
  }

  /**
   * Check if access token exists
   * In production: Always returns true if user data exists (tokens are in httpOnly cookies)
   * In development: Checks localStorage
   */
  static hasAccessToken(): boolean {
    if (isProduction()) {
      // In production, we can't check httpOnly cookies from JS
      // Use presence of user data as proxy for authentication
      return !!this.getUserData();
    }
    return !!this.getAccessToken();
  }


  static hasRefreshToken(): boolean {
    if (isProduction()) {
      return !!this.getUserData();
    }
    return !!this.getRefreshToken();
  }

  /**
   * Check if we're running on localhost
   */
  static isLocalhost(): boolean {
    return (
      window.location.hostname === 'localhost' ||
      window.location.hostname === '127.0.0.1' ||
      window.location.hostname === ''
    );
  }

  /**
   * Check if we're in production mode
   */
  static isProduction(): boolean {
    return isProduction();
  }

  /**
   * Set authentication error state (e.g. "SESSION_SUPERSEDED")
   * Used to flag specific fatal errors without immediately clearing all state
   */
  static setAuthError(error: string | null): void {
    if (error) {
      sessionStorage.setItem('__auth_error__', error);
    } else {
      sessionStorage.removeItem('__auth_error__');
    }
  }

  /**
   * Get authentication error state
   */
  static getAuthError(): string | null {
    return sessionStorage.getItem('__auth_error__');
  }
}

/**
 * Cookie utility for browser-side cookie management
 * Note: Backend sets httpOnly cookies, these utilities are for client-side access if needed
 */
export const CookieManager = {
  set(name: string, value: string, days: number = 7): void {
    cookieUtils.set(name, value, days);
  },
  get(name: string): string | null {
    return cookieUtils.get(name);
  },
  remove(name: string): void {
    cookieUtils.remove(name);
  },
  clearAll(): void {
    cookieUtils.clearAll();
  },
};

/**
 * Check if token is expired (with buffer time)
 */
export function isTokenExpired(token: string | null, bufferMinutes: number = 5): boolean {
  if (!token) return true;

  try {
    const parts = token.split('.');
    if (parts.length !== 3 || !parts[1]) return true;
    const payload = JSON.parse(atob(parts[1]));
    const exp = payload.exp * 1000; // Convert to milliseconds
    const now = Date.now();
    const buffer = bufferMinutes * 60 * 1000;
    return exp - now < buffer;
  } catch {
    return true;
  }
}

/**
 * Get token expiration time
 */
export function getTokenExpiration(token: string | null): Date | null {
  if (!token) return null;

  try {
    const parts = token.split('.');
    if (parts.length !== 3 || !parts[1]) return null;
    const payload = JSON.parse(atob(parts[1]));
    return new Date(payload.exp * 1000);
  } catch {
    return null;
  }
}

