import { JWTPayload, UserInfo } from '@/types';
import { appBridge } from './appBridge';
import { jwtDecoder } from './jwtDecoder';

const ACCESS_TOKEN_KEY = 'nice_access_token';
const REFRESH_TOKEN_KEY = 'nice_refresh_token';

export class TokenManager {
  private static instance: TokenManager;
  
  private constructor() {}
  
  static getInstance(): TokenManager {
    if (!TokenManager.instance) {
      TokenManager.instance = new TokenManager();
    }
    return TokenManager.instance;
  }

  setTokens(accessToken: string, refreshToken: string): void {
    localStorage.setItem(ACCESS_TOKEN_KEY, accessToken);
    localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
    this.saveTokensToAppBridge(accessToken, refreshToken);
  }

  getAccessToken(): string | null {
    return localStorage.getItem(ACCESS_TOKEN_KEY);
  }

  getRefreshToken(): string | null {
    return localStorage.getItem(REFRESH_TOKEN_KEY);
  }

  clearTokens(): void {
    localStorage.removeItem(ACCESS_TOKEN_KEY);
    localStorage.removeItem(REFRESH_TOKEN_KEY);
  }

  isTokenExpired(token: string): boolean {
    return jwtDecoder.isExpired(token);
  }

  isAccessTokenExpired(): boolean {
    const token = this.getAccessToken();
    if (!token) return true;
    return this.isTokenExpired(token);
  }

  isRefreshTokenExpired(): boolean {
    const token = this.getRefreshToken();
    if (!token) return true;
    return this.isTokenExpired(token);
  }

  decodeToken(token: string): JWTPayload | null {
    return jwtDecoder.decode(token);
  }

  getUserInfoFromToken(token?: string): UserInfo | null {
    const accessToken = token || this.getAccessToken();
    if (!accessToken) return null;

    const decoded = this.decodeToken(accessToken);
    if (!decoded) return null;

    return {
      id: decoded.userId,
      email: decoded.email,
      name: '', // 토큰에서 이름을 가져오지 않으므로 빈 문자열
      role: decoded.role,
      createdAt: '',
      updatedAt: ''
    };
  }

  getTokenExpirationTime(token: string): number | null {
    return jwtDecoder.getExpiration(token);
  }

  getTimeUntilExpiration(token: string): number {
    return jwtDecoder.getTimeUntilExpiration(token);
  }

  shouldRefreshToken(): boolean {
    const accessToken = this.getAccessToken();
    if (!accessToken) return false;

    const timeUntilExpiration = this.getTimeUntilExpiration(accessToken);
    // 토큰이 5분 이내에 만료되면 갱신
    const REFRESH_BUFFER_SECONDS = 5 * 60; // 5 minutes
    return timeUntilExpiration < REFRESH_BUFFER_SECONDS;
  }

  hasValidTokens(): boolean {
    const accessToken = this.getAccessToken();
    const refreshToken = this.getRefreshToken();
    
    if (!accessToken || !refreshToken) return false;
    
    // 리프레시 토큰이 유효하면 액세스 토큰은 갱신 가능
    return !this.isRefreshTokenExpired();
  }

  async refreshTokens(): Promise<{accessToken: string, refreshToken: string}> {
    const refreshToken = this.getRefreshToken();
    if (!refreshToken) {
      throw new Error('No refresh token available');
    }

    const response = await fetch('http://3.35.79.250:8090/auth/v1/refresh', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ refreshToken }),
    });

    if (!response.ok) {
      throw new Error(`Token refresh failed: ${response.status}`);
    }

    const data = await response.json();
    const newAccessToken = data.accessToken;
    const newRefreshToken = data.refreshToken;

    this.setTokens(newAccessToken, newRefreshToken);

    return { accessToken: newAccessToken, refreshToken: newRefreshToken };
  }

  async makeAuthenticatedRequest(url: string, options: RequestInit = {}): Promise<Response> {
    let accessToken = this.getAccessToken();
    
    if (!accessToken || this.isAccessTokenExpired()) {
      try {
        const refreshed = await this.refreshTokens();
        accessToken = refreshed.accessToken;
      } catch (error) {
        this.clearTokens();
        throw new Error('Authentication failed - please log in again');
      }
    }

    const requestOptions = {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': `Bearer ${accessToken}`,
      },
    };

    const response = await fetch(url, requestOptions);

    if (response.status === 401) {
      try {
        const refreshed = await this.refreshTokens();
        const retryOptions = {
          ...requestOptions,
          headers: {
            ...requestOptions.headers,
            'Authorization': `Bearer ${refreshed.accessToken}`,
          },
        };
        return await fetch(url, retryOptions);
      } catch (error) {
        this.clearTokens();
        throw new Error('Authentication failed - please log in again');
      }
    }

    return response;
  }

  private async saveTokensToAppBridge(accessToken: string, refreshToken: string): Promise<void> {
    try {
      if (appBridge.isNativeEnvironment()) {
        await Promise.all([
          appBridge.setStorage(ACCESS_TOKEN_KEY, accessToken),
          appBridge.setStorage(REFRESH_TOKEN_KEY, refreshToken)
        ]);
      }
    } catch (error) {
      console.error('Failed to save tokens to AppBridge:', error);
    }
  }
}

export const tokenManager = TokenManager.getInstance();