/**
 * HTTP客户端
 * 用于与后端API进行通信，支持拦截器、超时控制等功能
 */

/**
 * HTTP请求方法类型
 */
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';

/**
 * HTTP客户端配置
 */
export interface HttpClientConfig {
  /** 基础URL */
  baseURL?: string;
  /** 默认请求头 */
  headers?: Record<string, string>;
  /** 超时时间(毫秒) */
  timeout?: number;
  /** 是否携带凭证 */
  withCredentials?: boolean;
  /** 租户ID */
  tenantId?: string;
}

/**
 * HTTP请求选项
 */
export interface HttpRequestOptions {
  /** 请求方法 */
  method: HttpMethod;
  /** 请求URL */
  url: string;
  /** 请求头 */
  headers?: Record<string, string>;
  /** 请求体 */
  body?: any;
  /** 是否需要认证 */
  needAuth?: boolean;
  /** 超时时间 */
  timeout?: number;
  /** 是否携带凭证 */
  withCredentials?: boolean;
}

/**
 * HTTP响应类型
 */
export interface HttpResponse<T = any> {
  /** 状态码 */
  status: number;
  /** 状态文本 */
  statusText: string;
  /** 响应体 */
  data: T;
  /** 响应头 */
  headers: Record<string, string>;
}

/**
 * 请求拦截器
 */
export interface RequestInterceptor {
  /** 请求前拦截 */
  onRequest?: (options: HttpRequestOptions) => HttpRequestOptions | Promise<HttpRequestOptions>;
  /** 请求错误拦截 */
  onRequestError?: (error: any) => any;
}

/**
 * 响应拦截器
 */
export interface ResponseInterceptor<T = any> {
  /** 响应后拦截 */
  onResponse?: (response: HttpResponse<T>) => HttpResponse<T> | Promise<HttpResponse<T>>;
  /** 响应错误拦截 */
  onResponseError?: (error: HttpError) => any;
}

/**
 * HTTP错误类型
 */
export class HttpError extends Error {
  /** 状态码 */
  public status: number;
  /** 状态文本 */
  public statusText: string;
  /** 错误数据 */
  public data: any;
  /** 错误代码 */
  public code?: string;

  /**
   * 构造函数
   * @param message 错误信息
   * @param status 状态码
   * @param statusText 状态文本
   * @param data 错误数据
   * @param code 错误代码
   */
  constructor(
    message: string, 
    status: number = 0, 
    statusText: string = 'Unknown Error', 
    data: any = null,
    code?: string
  ) {
    super(message);
    this.name = 'HttpError';
    this.status = status;
    this.statusText = statusText;
    this.data = data;
    this.code = code;
    
    // 保持堆栈跟踪
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, HttpError);
    }
  }
}

/**
 * HTTP客户端类
 */
export class HttpClient {
  private config: Required<HttpClientConfig>;
  private tokenGetter?: () => string | null;
  private requestInterceptors: RequestInterceptor[] = [];
  private responseInterceptors: ResponseInterceptor[] = [];

  /**
   * 构造函数
   * @param config 客户端配置
   */
  constructor(config: HttpClientConfig = {}) {
    this.config = {
      baseURL: '',
      headers: {
        'Content-Type': 'application/json'
      },
      timeout: 10000,
      withCredentials: true,
      tenantId: '',
      ...config
    };
  }

  /**
   * 设置Token获取函数
   * @param tokenGetter Token获取函数
   */
  setTokenGetter(tokenGetter: () => string | null): void {
    this.tokenGetter = tokenGetter;
  }

  /**
   * 设置租户ID
   * @param tenantId 租户ID
   */
  setTenantId(tenantId?: string): void {
    this.config.tenantId = tenantId || '';
  }

  /**
   * 添加请求拦截器
   * @param interceptor 请求拦截器
   */
  addRequestInterceptor(interceptor: RequestInterceptor): void {
    this.requestInterceptors.push(interceptor);
  }

  /**
   * 添加响应拦截器
   * @param interceptor 响应拦截器
   */
  addResponseInterceptor(interceptor: ResponseInterceptor): void {
    this.responseInterceptors.push(interceptor);
  }

  /**
   * 移除请求拦截器
   * @param interceptor 要移除的拦截器
   */
  removeRequestInterceptor(interceptor: RequestInterceptor): void {
    const index = this.requestInterceptors.indexOf(interceptor);
    if (index > -1) {
      this.requestInterceptors.splice(index, 1);
    }
  }

  /**
   * 移除响应拦截器
   * @param interceptor 要移除的拦截器
   */
  removeResponseInterceptor(interceptor: ResponseInterceptor): void {
    const index = this.responseInterceptors.indexOf(interceptor);
    if (index > -1) {
      this.responseInterceptors.splice(index, 1);
    }
  }

  /**
   * 发送HTTP请求
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async request<T = any>(options: HttpRequestOptions): Promise<HttpResponse<T>> {
    // 合并配置
    const mergedOptions = this.mergeOptions(options);

    try {
      // 执行请求拦截器
      let processedOptions = await this.executeRequestInterceptors(mergedOptions);
      
      // 构建完整URL
      const fullUrl = this.buildFullUrl(processedOptions.url);
      
      // 构建请求配置
      const fetchOptions = this.buildFetchOptions(processedOptions);
      
      // 发送请求（包含超时控制）
      const response = await this.fetchWithTimeout(
        fullUrl, 
        fetchOptions, 
        processedOptions.timeout ?? this.config.timeout
      );
      
      const responseData = await this.parseResponse(response);
      
      // 构建响应对象
      let httpResponse: HttpResponse<T> = {
        status: response.status,
        statusText: response.statusText,
        data: responseData,
        headers: this.parseHeaders(response.headers)
      };

      // 处理业务逻辑
      httpResponse = this.handleBusinessLogic(httpResponse);
      
      // 执行响应拦截器
      httpResponse = await this.executeResponseInterceptors(httpResponse);
      
      return httpResponse;
      
    } catch (error) {
      // 执行响应错误拦截器
      return this.executeResponseErrorInterceptors(error);
    }
  }
  


  /**
   * 合并请求选项与默认配置
   * @param options 请求选项
   * @returns 合并后的选项
   */
  private mergeOptions(options: HttpRequestOptions): HttpRequestOptions {
    return {
      method: options.method,
      url: options.url,
      headers: {
        ...this.config.headers,
        ...options.headers
      },
      body: options.body,
      needAuth: options.needAuth ?? true,
      timeout: options.timeout ?? this.config.timeout,
      withCredentials: options.withCredentials ?? this.config.withCredentials
    };
  }

  /**
   * 构建完整URL
   * @param url 相对URL或绝对URL
   * @returns 完整URL
   */
  private buildFullUrl(url: string): string {
    if (url.startsWith('http://') || url.startsWith('https://')) {
      return url;
    }
    return this.config.baseURL ? `${this.config.baseURL}${url}` : url;
  }

  /**
   * 构建fetch选项
   * @param options 处理后的请求选项
   * @returns fetch配置
   */
  private buildFetchOptions(options: HttpRequestOptions): RequestInit {
    const requestHeaders: Record<string, string> = { ...options.headers };

    // 添加认证头
    if (options.needAuth && this.tokenGetter) {
      const token = this.tokenGetter();
      if (token) {
        requestHeaders.Authorization = token;
      }
    }

    // 添加租户ID头
    if (this.config.tenantId) {
      requestHeaders['tenant-id'] = this.config.tenantId;
    }

    const fetchOptions: RequestInit = {
      method: options.method,
      headers: requestHeaders,
      credentials: options.withCredentials ? 'include' : 'omit'
    };

    // 添加请求体
    if (options.body && ['POST', 'PUT', 'PATCH'].includes(options.method)) {
      fetchOptions.body = typeof options.body === 'string' 
        ? options.body 
        : JSON.stringify(options.body);
    }

    return fetchOptions;
  }

  /**
   * 带超时控制的fetch
   * @param url 请求URL
   * @param options fetch选项
   * @param timeout 超时时间
   * @returns Promise<Response>
   */
  private async fetchWithTimeout(
    url: string, 
    options: RequestInit, 
    timeout: number
  ): Promise<Response> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);
    
    try {
      const response = await fetch(url, {
        ...options,
        signal: controller.signal
      });
      clearTimeout(timeoutId);
      return response;
    } catch (error) {
      clearTimeout(timeoutId);
      if (error instanceof Error && error.name === 'AbortError') {
        throw new HttpError(
          `Request timeout after ${timeout}ms`,
          408,
          'Request Timeout',
          null,
          'TIMEOUT_ERROR'
        );
      }
      throw error;
    }
  }

  /**
   * 处理业务逻辑
   * @param response 响应对象
   * @returns 处理后的响应
   */
  private handleBusinessLogic<T = any>(response: HttpResponse<T>): HttpResponse<T> {
    const { data, status } = response;
    
    // 检查是否为业务响应结构 { code, msg, data }
    if (this.isBusinessResponse(data)) {
      const { code, msg, data: businessData } = data;
      
      // 检查业务状态码
      if (code !== 0 && code !== 200 && code !== '0' && code !== '200') {
        // 业务错误
        throw new HttpError(
          msg || `Business Error: ${code}`,
          status,
          response.statusText,
          data,
          `BUSINESS_ERROR_${code}`
        );
      }
      
      // 业务成功，返回data字段
      return {
        ...response,
        data: businessData as T
      };
    }
    
    return response;
  }

  /**
   * 检查是否为业务响应结构
   * @param data 响应数据
   * @returns boolean 是否为业务响应结构
   */
  private isBusinessResponse(data: any): data is { code: any; msg: string; data: any } {
    return (
      typeof data === 'object' && 
      data !== null && 
      ('code' in data) && 
      ('msg' in data) && 
      ('data' in data)
    );
  }

  /**
   * 执行请求拦截器
   * @param options 请求选项
   * @returns 处理后的请求选项
   */
  private async executeRequestInterceptors(options: HttpRequestOptions): Promise<HttpRequestOptions> {
    let processedOptions = options;
    
    for (const interceptor of this.requestInterceptors) {
      try {
        if (interceptor.onRequest) {
          processedOptions = await interceptor.onRequest(processedOptions);
        }
      } catch (error) {
        if (interceptor.onRequestError) {
          interceptor.onRequestError(error);
        }
        throw error;
      }
    }
    
    return processedOptions;
  }

  /**
   * 执行响应拦截器
   * @param response 响应对象
   * @returns 处理后的响应对象
   */
  private async executeResponseInterceptors<T = any>(response: HttpResponse<T>): Promise<HttpResponse<T>> {
    let processedResponse = response;
    
    for (const interceptor of this.responseInterceptors) {
      try {
        if (interceptor.onResponse) {
          processedResponse = await interceptor.onResponse(processedResponse);
        }
      } catch (error) {
        if (interceptor.onResponseError) {
          return interceptor.onResponseError(error as HttpError);
        }
        throw error;
      }
    }
    
    return processedResponse;
  }

  /**
   * 执行响应错误拦截器
   * @param error 错误对象
   * @returns Promise<never>
   */
  private executeResponseErrorInterceptors(error: any): never {
    let processedError = error;
    
    for (const interceptor of this.responseInterceptors) {
      if (interceptor.onResponseError) {
        try {
          processedError = interceptor.onResponseError(processedError);
        } catch (interceptorError) {
          processedError = interceptorError;
        }
      }
    }
    
    if (processedError instanceof HttpError) {
      throw processedError;
    }
    
    // 转换为HttpError
    throw new HttpError(
      processedError instanceof Error ? processedError.message : 'Unknown Error',
      0,
      'Unknown Error',
      null,
      'UNKNOWN_ERROR'
    );
  }

  /**
   * HEAD请求
   * @param url 请求URL
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async head<T = any>(url: string, options?: Omit<HttpRequestOptions, 'method' | 'url'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'HEAD',
      url,
      ...options
    });
  }

  /**
   * OPTIONS请求
   * @param url 请求URL
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async options<T = any>(url: string, options?: Omit<HttpRequestOptions, 'method' | 'url'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'OPTIONS',
      url,
      ...options
    });
  }

  /**
   * GET请求
   * @param url 请求URL
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async get<T = any>(url: string, options?: Omit<HttpRequestOptions, 'method' | 'url'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'GET',
      url,
      ...options
    });
  }

  /**
   * POST请求
   * @param url 请求URL
   * @param body 请求体
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async post<T = any>(url: string, body?: any, options?: Omit<HttpRequestOptions, 'method' | 'url' | 'body'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'POST',
      url,
      body,
      ...options
    });
  }

  /**
   * PUT请求
   * @param url 请求URL
   * @param body 请求体
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async put<T = any>(url: string, body?: any, options?: Omit<HttpRequestOptions, 'method' | 'url' | 'body'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'PUT',
      url,
      body,
      ...options
    });
  }

  /**
   * DELETE请求
   * @param url 请求URL
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async delete<T = any>(url: string, options?: Omit<HttpRequestOptions, 'method' | 'url'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'DELETE',
      url,
      ...options
    });
  }

  /**
   * PATCH请求
   * @param url 请求URL
   * @param body 请求体
   * @param options 请求选项
   * @returns Promise<HttpResponse<T>> 响应结果
   */
  async patch<T = any>(url: string, body?: any, options?: Omit<HttpRequestOptions, 'method' | 'url' | 'body'>): Promise<HttpResponse<T>> {
    return this.request<T>({
      method: 'PATCH',
      url,
      body,
      ...options
    });
  }

  /**
   * 创建带基础URL的客户端实例
   * @param baseURL 基础URL
   * @param config 其他配置
   * @returns HttpClient 新的客户端实例
   */
  static create(baseURL: string, config?: Omit<HttpClientConfig, 'baseURL'>): HttpClient {
    return new HttpClient({
      baseURL,
      ...config
    });
  }

  /**
   * 获取当前配置
   * @returns HttpClientConfig 当前配置
   */
  getConfig(): HttpClientConfig {
    return { ...this.config };
  }

  /**
   * 更新配置
   * @param config 新的配置
   */
  updateConfig(config: Partial<HttpClientConfig>): void {
    this.config = {
      ...this.config,
      ...config
    };
  }

  /**
   * 解析响应体
   * @param response 响应对象
   * @returns Promise<any> 解析后的响应体
   */
  private async parseResponse(response: Response): Promise<any> {
    const contentType = response.headers.get('content-type') || '';
    
    if (contentType.includes('application/json')) {
      return response.json();
    } else if (contentType.includes('text/')) {
      return response.text();
    } else {
      return response.blob();
    }
  }

  /**
   * 解析响应头
   * @param headers 响应头对象
   * @returns Record<string, string> 解析后的响应头
   */
  private parseHeaders(headers: Headers): Record<string, string> {
    const result: Record<string, string> = {};
    headers.forEach((value, key) => {
      result[key] = value;
    });
    return result;
  }
}
