/**
 * 认证核心逻辑
 * 实现OAuth2授权码模式的完整流程
 */

import {EventType, RouterInfo, SDKConfig, UserInfo} from '../types';
import {TokenManager} from './token';
import {HttpClient} from './http';
import {Storage} from '../utils/storage';
import {buildQueryParams, isCallbackUrl, parseQueryParams} from '../utils/url';

/**
 * 认证核心类
 */
export class Auth {
  private config: SDKConfig | null = null;
  private tokenManager: TokenManager;
  private httpClient: HttpClient;
  private storage: Storage;
  private eventHandlers: Record<EventType, Function[]> = {
    login: [],
    logout: [],
    tokenExpired: []
  };
  private userInfoCache: UserInfo | null = null;

  /**
   * 构造函数
   * @param storage 存储实例
   */
  constructor(storage: Storage) {
    this.storage = storage;
    // 先创建HttpClient，初始时tokenManager为undefined
    this.httpClient = new HttpClient(() => this.tokenManager.getToken() || null);
    // 然后创建TokenManager
    this.tokenManager = new TokenManager(storage);
  }

  /**
   * 初始化SDK配置
   * @param config SDK配置选项
   */
  init(config: SDKConfig): void {
    this.config = config;
    // 设置租户ID到HTTP客户端
    this.httpClient.setTenantId(config.tenantId);
  }

  getToken():string | null{
    return this.tokenManager.getToken()
  }

  /**
   * 触发登录流程
   * @param redirectUri 可选的重定向URL，覆盖初始化时的配置
   */
  async login(redirectUri?: string): Promise<void> {
    if (!this.config) {
      throw new Error('SDK not initialized');
    }
    const registrationId = this.config.registrationId || 'idp'
    const basepath = this.config.basepath || ''
    const path = `${basepath}/oauth2/authorization/${registrationId}`
    const tokenResponse = await this.httpClient.get(path,{needAuth:false})
    const redirect = tokenResponse.data.redirect_url
    const params = parseQueryParams(redirect)
    this.storage.set(params.state,window.location.href)
    window.location.href = redirect
  }

  /**
   * 退出登录
   */
  async logout(): Promise<void> {
    if (!this.config) {
      throw new Error('SDK not initialized');
    }
    // 清除本地存储的Token和用户信息
    this.tokenManager.clearToken();
    this.userInfoCache = null;
    this.storage.remove('userInfo');
    const basepath = this.config.basepath || ''
    await this.httpClient.post(`${basepath}/logout`,null,{needAuth:true})
    // 触发退出事件
    this.emit('logout');
    window.location.href = this.config.idpLogoutUrl+'?redirect='+this.config.homePage;
  }

  /**
   * 处理授权回调
   * @returns Promise<UserInfo> 用户信息
   */
  async handleCallback(): Promise<void> {
    if (!this.config) {
      throw new Error('SDK not initialized');
    }

    const params = parseQueryParams();
    
    // 检查是否有错误
    if (params.error) {
      throw new Error(`Authorization error: ${params.error} - ${params.error_description || ''}`);
    }

    // 检查是否有授权码
    if (!params.code) {
      throw new Error('Authorization code not found');
    }

      const registrationId = this.config.registrationId || 'idp'
      const basepath = this.config.basepath || ''
      const callback = `${basepath}/login/oauth2/code/${registrationId}${buildQueryParams(params)}`
      const tokenResponse = await this.httpClient.get(callback,{
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        needAuth: false
      })
      // 触发登录事件
      this.emit('login');
      this.storage.set('userInfo', tokenResponse.data.data);
      this.tokenManager.saveToken(tokenResponse.headers['authorization']||tokenResponse.headers['Authorization'])
      let url = this.config.homePage
      if(params.state){
        url = this.storage.get(params.state) || url;
      }
      window.location.href = url;

  }

  async getRoutes(): Promise<RouterInfo> {
    if (!this.config) {
      throw new Error('SDK not initialized');
    }
    const basepath = this.config.basepath || ''
    const tokenResponse = await this.httpClient.get(`${basepath}/idp/routes`,{needAuth:true})
    if(tokenResponse.status===401){
      await this.logout()
    }
    return tokenResponse.data.data

  }
  /**
   * 获取用户信息
   * @returns UserInfo 用户信息
   */
   getUserInfo(): UserInfo {
    return this.storage.get("userInfo");
  }




  /**
   * 检查用户是否有指定角色
   * @param role 角色编码或角色编码列表
   * @returns Promise<boolean> 是否有指定角色
   */
  async hasRole(role: string | string[]): Promise<boolean> {
    if (!this.isAuthenticated()) {
      return false;
    }

    const userInfo:UserInfo = this.storage.get("userInfo");
    const roleCodes = userInfo.roles||[];

    if (Array.isArray(role)) {
      // 检查是否有任一角色
      return role.some(r => roleCodes.includes(r));
    }

    // 检查是否有单个角色
    return roleCodes.includes(role);
  }

  /**
   * 检查用户是否有所有指定角色
   * @param roles 角色编码列表
   * @returns Promise<boolean> 是否有所有指定角色
   */
  async hasAllRoles(roles: string[]): Promise<boolean> {
    if (!this.isAuthenticated()) {
      return false;
    }

    const userInfo:UserInfo = this.storage.get("userInfo");
    const roleCodes = userInfo.roles||[];
    // 检查是否有所有角色
    return roles.every(r => roleCodes.includes(r));
  }

  /**
   * 检查用户是否有指定权限
   * @param permission 权限标识或权限标识列表
   * @returns Promise<boolean> 是否有指定权限
   */
  async hasPermission(permission: string | string[]): Promise<boolean> {
    if (!this.isAuthenticated()) {
      return false;
    }

    const userInfo:UserInfo = this.storage.get("userInfo");
    const permissions = userInfo.permissions||[];

    if (Array.isArray(permission)) {
      // 检查是否有任一权限
      return permission.some(p => permissions.includes(p));
    }

    // 检查是否有单个权限
    return permissions.includes(permission);
  }

  /**
   * 检查用户是否有所有指定权限
   * @param permissions 权限标识列表
   * @returns Promise<boolean> 是否有所有指定权限
   */
  async hasAllPermissions(permissions: string[]): Promise<boolean> {
    if (!this.isAuthenticated()) {
      return false;
    }

    const userInfo:UserInfo = this.storage.get("userInfo");
    const userPermissions = userInfo.permissions||[];

    // 检查是否有所有权限
    return permissions.every(p => userPermissions.includes(p));
  }

  /**
   * 检查用户是否已认证
   * @returns boolean 是否已认证
   */
  isAuthenticated(): boolean {
    // 检查Token是否存在且未过期
    return !!this.tokenManager.getToken();
  }

  /**
   * 事件监听
   * @param event 事件类型
   * @param callback 回调函数
   */
  on(event: EventType, callback: Function): void {
    this.eventHandlers[event].push(callback);
  }

  /**
   * 移除事件监听
   * @param event 事件类型
   * @param callback 回调函数
   */
  off(event: EventType, callback: Function): void {
    this.eventHandlers[event] = this.eventHandlers[event].filter(handler => handler !== callback);
  }

  /**
   * 触发事件
   * @param event 事件类型
   * @param data 事件数据
   */
  private emit(event: EventType, data?: any): void {
    this.eventHandlers[event].forEach(handler => {
      try {
        handler(data);
      } catch (error) {
        console.error(`Error in ${event} event handler:`, error);
      }
    });
  }

  /**
   * 检查当前URL是否为授权回调
   * @returns boolean 是否为授权回调
   */
  isCallback(): boolean {
    return isCallbackUrl();
  }
}
