/**
 * @file Axios HTTP 客户端实现
 * @description 基于 Axios 的 HTTP 客户端实现
 * @author JunBin.Yang
 */

import axios, { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from '@ohos/axios';
import { HttpClient, RequestOptions } from './HttpClient';
import { NetworkConfig, DEFAULT_NETWORK_CONFIG } from './NetworkConfig';
import { HttpInterceptor } from './HttpInterceptor';
import { Unknown, ObjectAssign } from "@core/common";
import { Logger } from "@core/util";

const TAG: string = 'AxiosHttpClient';

/**
 * 基于 Axios 的 HTTP 客户端实现
 */
export class AxiosHttpClient implements HttpClient {
  /**
   * Axios 实例
   */
  private axiosInstance: AxiosInstance;

  /**
   * 网络配置
   */
  private config: NetworkConfig;

  /**
   * 拦截器列表
   */
  private interceptors: HttpInterceptor[] = [];

  /**
   * 拦截器 ID 映射
   */
  private interceptorIds: Map<HttpInterceptor, HttpID> = new Map();

  /**
   * 构造函数
   * @param config 网络配置
   */
  constructor(config?: Partial<NetworkConfig>) {
    this.config = ObjectAssign({} as NetworkConfig, DEFAULT_NETWORK_CONFIG, config);
    this.axiosInstance = axios.create({
      baseURL: this.config.baseUrl,
      timeout: this.config.timeout,
      headers: this.config.headers
    });
  }

  /**
   * GET 请求
   * @param url 请求地址
   * @param options 请求选项
   * @returns 响应数据
   */
  async get<T>(url: string, options?: RequestOptions): Promise<T> {
    this.logRequest('GET', url, options);
    const response: AxiosResponse<T> = await this.axiosInstance.get<T>(url, {
      headers: options?.headers,
      timeout: options?.timeout,
      params: options?.params
    });
    this.logResponse('GET', url, response);
    return response.data;
  }

  /**
   * POST 请求
   * @param url 请求地址
   * @param data 请求体
   * @param options 请求选项
   * @returns 响应数据
   */
  async post<T>(url: string, data?: Unknown, options?: RequestOptions): Promise<T> {
    this.logRequest('POST', url, options, data);
    const response: AxiosResponse<T> = await this.axiosInstance.post<T>(url, data, {
      headers: options?.headers,
      timeout: options?.timeout,
      params: options?.params
    });
    this.logResponse('POST', url, response);
    return response.data;
  }

  /**
   * PUT 请求
   * @param url 请求地址
   * @param data 请求体
   * @param options 请求选项
   * @returns 响应数据
   */
  async put<T>(url: string, data?: Unknown, options?: RequestOptions): Promise<T> {
    this.logRequest('PUT', url, options, data);
    const response: AxiosResponse<T> = await this.axiosInstance.put<T>(url, data, {
      headers: options?.headers,
      timeout: options?.timeout,
      params: options?.params
    });
    this.logResponse('PUT', url, response);
    return response.data;
  }

  /**
   * DELETE 请求
   * @param url 请求地址
   * @param options 请求选项
   * @returns 响应数据
   */
  async delete<T>(url: string, options?: RequestOptions): Promise<T> {
    this.logRequest('DELETE', url, options);
    const response: AxiosResponse<T> = await this.axiosInstance.delete<T>(url, {
      headers: options?.headers,
      timeout: options?.timeout,
      params: options?.params
    });
    this.logResponse('DELETE', url, response);
    return response.data;
  }

  /**
   * 添加拦截器
   * @param interceptor 拦截器实例
   */
  addInterceptor(interceptor: HttpInterceptor): void {
    // 按优先级排序插入
    const priority = interceptor.priority ?? 100;
    let insertIndex = this.interceptors.findIndex(i => (i.priority ?? 100) > priority);
    if (insertIndex === -1) {
      insertIndex = this.interceptors.length;
    }
    this.interceptors.splice(insertIndex, 0, interceptor);

    const ids: HttpID = {};

    // 注册请求拦截器
    if (interceptor.onRequest || interceptor.onRequestError) {
      ids.request = this.axiosInstance.interceptors.request.use(
        interceptor.onRequest
          ? (config: InternalAxiosRequestConfig) => interceptor.onRequest!(config)
          : undefined,
        interceptor.onRequestError
      );
    }

    // 注册响应拦截器
    if (interceptor.onResponse || interceptor.onResponseError) {
      ids.response = this.axiosInstance.interceptors.response.use(
        interceptor.onResponse
          ? (response: AxiosResponse) => interceptor.onResponse!(response)
          : undefined,
        interceptor.onResponseError
      );
    }

    this.interceptorIds.set(interceptor, ids);

    if (this.config.enableLog) {
      Logger.info(`Interceptor added: ${interceptor.name ?? 'unnamed'}`, TAG);
    }
  }

  /**
   * 移除拦截器
   * @param interceptor 拦截器实例
   */
  removeInterceptor(interceptor: HttpInterceptor): void {
    const index = this.interceptors.indexOf(interceptor);
    if (index !== -1) {
      this.interceptors.splice(index, 1);
    }

    const ids = this.interceptorIds.get(interceptor);
    if (ids) {
      if (ids.request !== undefined) {
        this.axiosInstance.interceptors.request.eject(ids.request);
      }
      if (ids.response !== undefined) {
        this.axiosInstance.interceptors.response.eject(ids.response);
      }
      this.interceptorIds.delete(interceptor);
    }

    if (this.config.enableLog) {
      Logger.info(`Interceptor removed: ${interceptor.name ?? 'unnamed'}`, TAG);
    }
  }

  /**
   * 获取当前配置
   * @returns 网络配置
   */
  getConfig(): NetworkConfig {
    return ObjectAssign({} as NetworkConfig, this.config);
  }

  /**
   * 更新配置
   * @param config 新配置
   */
  updateConfig(config: Partial<NetworkConfig>): void {
    this.config = ObjectAssign({} as NetworkConfig, this.config, config);
    // 更新 Axios 实例配置
    if (config.baseUrl !== undefined) {
      this.axiosInstance.defaults.baseURL = config.baseUrl;
    }
    if (config.timeout !== undefined) {
      this.axiosInstance.defaults.timeout = config.timeout;
    }
    if (config.headers !== undefined) {
      this.axiosInstance.defaults.headers.common = ObjectAssign({}, this.axiosInstance.defaults.headers.common, config.headers);
    }
  }

  /**
   * 获取 Axios 实例(高级用法)
   * @returns Axios 实例
   */
  getAxiosInstance(): AxiosInstance {
    return this.axiosInstance;
  }

  /**
   * 记录请求日志
   */
  private logRequest(method: string, url: string, options?: RequestOptions, data?: Unknown): void {
    if (this.config.enableLog) {
      Logger.info(`[${method}] ${url}`, TAG);
      if (options?.params) {
        Logger.info(`Params: ${JSON.stringify(options.params)}`, TAG);
      }
      if (data) {
        Logger.info(`Body: ${JSON.stringify(data)}`, TAG);
      }
    }
  }

  /**
   * 记录响应日志
   */
  private logResponse(method: string, url: string, response: AxiosResponse): void {
    if (this.config.enableLog) {
      Logger.info(`[${method}] ${url} -> ${response.status}`, TAG);
      Logger.info(`Response: ${JSON.stringify(response.data)}`, TAG);
    }
  }
}

interface HttpID {
  request?: number;
  response?: number;
}