import Taro from '@tarojs/taro'
import { BaseUrl, TenantId } from "@/config/app";

// 请求配置接口
interface RequestConfig {
  url: string;
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  data?: any;
  header?: Record<string, string>;
  timeout?: number;
  retry?: number;
  showLoading?: boolean;
  showError?: boolean;
  returnRaw?: boolean; // 是否返回原始响应数据
}

// API响应接口
interface ApiResponse<T = any> {
  code: number;
  message?: string;
  data?: T;
}

// 错误类型枚举
enum ErrorType {
  NETWORK_ERROR = 'NETWORK_ERROR',
  TIMEOUT_ERROR = 'TIMEOUT_ERROR',
  BUSINESS_ERROR = 'BUSINESS_ERROR',
  AUTH_ERROR = 'AUTH_ERROR',
  UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}

// 自定义错误类
class RequestError extends Error {
  public type: ErrorType;
  public code?: number;
  public data?: any;

  constructor(message: string, type: ErrorType, code?: number, data?: any) {
    super(message);
    this.name = 'RequestError';
    this.type = type;
    this.code = code;
    this.data = data;
  }
}

// 请求配置
const DEFAULT_CONFIG = {
  timeout: 10000, // 10秒超时
  retry: 2, // 重试2次
  showLoading: false,
  showError: true
};

let baseUrl = BaseUrl;

// 开发环境配置
if (process.env.NODE_ENV === 'development') {
  // baseUrl = 'http://localhost:9200/api'
}

// 请求拦截器
const requestInterceptor = (config: RequestConfig): RequestConfig => {
  // 添加认证token
  const token = Taro.getStorageSync('access_token');
  const tenantId = Taro.getStorageSync('TenantId') || TenantId;

  const defaultHeaders: Record<string, string> = {
    'Content-Type': 'application/json',
    'TenantId': tenantId
  };

  if (token) {
    defaultHeaders['Authorization'] = token;
  }

  config.header = { ...defaultHeaders, ...config.header };

  // 显示加载提示
  if (config.showLoading) {
    Taro.showLoading({ title: '加载中...' });
  }

  return config;
};

// 响应拦截器
const responseInterceptor = <T>(response: any, config: RequestConfig): T => {
  // 隐藏加载提示
  if (config.showLoading) {
    Taro.hideLoading();
  }

  const { statusCode, data } = response;

  // HTTP状态码检查
  if (statusCode !== 200) {
    throw new RequestError(
      `HTTP错误: ${statusCode}`,
      ErrorType.NETWORK_ERROR,
      statusCode,
      data
    );
  }

  // 如果没有数据，抛出错误
  if (!data) {
    throw new RequestError(
      '响应数据为空',
      ErrorType.NETWORK_ERROR,
      statusCode,
      data
    );
  }

  // 业务状态码检查
  if (typeof data === 'object' && 'code' in data) {
    const apiResponse = data as ApiResponse<T>;

    // 成功响应
    if (apiResponse.code === 0) {
      // 如果配置了返回原始响应，则返回完整响应
      if (config.returnRaw) {
        return data as T;
      }
      // 否则返回data部分
      return apiResponse.data as T;
    }

    // 认证错误
    if (apiResponse.code === 401 || apiResponse.code === 403) {
      handleAuthError();
      throw new RequestError(
        apiResponse.message || '认证失败',
        ErrorType.AUTH_ERROR,
        apiResponse.code,
        apiResponse.data
      );
    }

    // 业务错误
    throw new RequestError(
      apiResponse.message || '请求失败',
      ErrorType.BUSINESS_ERROR,
      apiResponse.code,
      apiResponse.data
    );
  }

  // 如果不是标准的API响应格式，直接返回数据
  return data as T;
};

// 处理认证错误
const handleAuthError = () => {
  // 清除本地存储的认证信息
  try {
    Taro.removeStorageSync('access_token');
    Taro.removeStorageSync('User');
    Taro.removeStorageSync('UserId');
    Taro.removeStorageSync('TenantId');
    Taro.removeStorageSync('Phone');
  } catch (error) {
    console.error('清除认证信息失败:', error);
  }

  // 显示提示并跳转到登录页
  Taro.showToast({
    title: '登录已过期，请重新登录',
    icon: 'none',
    duration: 2000
  });

  setTimeout(() => {
    Taro.reLaunch({ url: '/passport/login' });
  }, 2000);
};

// 错误处理
const handleError = (error: RequestError, config: RequestConfig) => {
  console.error('请求错误:', error);

  if (config.showLoading) {
    Taro.hideLoading();
  }

  if (config.showError) {
    let title = '请求失败';

    switch (error.type) {
      case ErrorType.NETWORK_ERROR:
        title = '网络连接失败';
        break;
      case ErrorType.TIMEOUT_ERROR:
        title = '请求超时';
        break;
      case ErrorType.BUSINESS_ERROR:
        title = error.message || '操作失败';
        break;
      case ErrorType.AUTH_ERROR:
        title = '认证失败';
        break;
      default:
        title = '未知错误';
    }

    Taro.showToast({
      title,
      icon: 'error',
      duration: 2000
    });
  }
};

// 重试机制
const retryRequest = async <T>(
  config: RequestConfig,
  retryCount: number = 0
): Promise<T> => {
  try {
    return await executeRequest<T>(config);
  } catch (error) {
    const requestError = error as RequestError;

    // 如果是认证错误或业务错误，不重试
    if (requestError.type === ErrorType.AUTH_ERROR ||
        requestError.type === ErrorType.BUSINESS_ERROR) {
      throw error;
    }

    // 如果还有重试次数
    if (retryCount < (config.retry || DEFAULT_CONFIG.retry)) {
      console.log(`请求失败，正在重试 ${retryCount + 1}/${config.retry || DEFAULT_CONFIG.retry}`);
      await new Promise(resolve => setTimeout(resolve, 1000 * (retryCount + 1))); // 递增延迟
      return retryRequest<T>(config, retryCount + 1);
    }

    throw error;
  }
};

// 执行请求
const executeRequest = <T>(config: RequestConfig): Promise<T> => {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new RequestError('请求超时', ErrorType.TIMEOUT_ERROR));
    }, config.timeout || DEFAULT_CONFIG.timeout);

    Taro.request({
      url: config.url,
      method: config.method || 'GET',
      data: config.data || {},
      header: config.header || {},
      success: (res) => {
        clearTimeout(timer);
        try {
          const result = responseInterceptor<T>(res, config);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      },
      fail: (err) => {
        clearTimeout(timer);
        reject(new RequestError(
          err.errMsg || '网络请求失败',
          ErrorType.NETWORK_ERROR,
          undefined,
          err
        ));
      }
    });
  });
};

// 主请求函数
export async function request<T>(options: RequestConfig): Promise<T> {
  try {
    // 请求拦截
    const config = requestInterceptor({ ...DEFAULT_CONFIG, ...options });

    // 执行请求（带重试）
    const result = await retryRequest<T>(config);
    return result;
  } catch (error) {
    const requestError = error as RequestError;
    handleError(requestError, options);
    throw requestError;
  }
}

// 构建完整URL
const buildUrl = (url: string): string => {
  if (url.indexOf('http') === -1) {
    return baseUrl + url;
  }
  return url;
};

// 构建查询参数
const buildQueryString = (params: Record<string, any>): string => {
  const queryString = Object.keys(params)
    .filter(key => params[key] !== undefined && params[key] !== null)
    .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
    .join('&');
  return queryString ? `?${queryString}` : '';
};

// GET请求 - 返回完整的ApiResult响应（适配后台生成的代码）
export function get<T>(url: string, params?: any, config?: Partial<RequestConfig>): Promise<T> {
  const fullUrl = buildUrl(url) + (params ? buildQueryString(params) : '');
  return request<T>({
    url: fullUrl,
    method: 'GET',
    returnRaw: true,
    ...config
  });
}

// POST请求 - 返回完整的ApiResult响应（适配后台生成的代码）
export function post<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'POST',
    data,
    returnRaw: true,
    ...config
  });
}

// PUT请求 - 返回完整的ApiResult响应（适配后台生成的代码）
export function put<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'PUT',
    data,
    returnRaw: true,
    ...config
  });
}

// PATCH请求 - 返回完整的ApiResult响应（适配后台生成的代码）
export function patch<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'PATCH',
    data,
    returnRaw: true,
    ...config
  });
}

// DELETE请求 - 返回完整的ApiResult响应（适配后台生成的代码）
export function del<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'DELETE',
    data,
    returnRaw: true,
    ...config
  });
}

// 便捷方法 - 自动提取data字段（用于不需要处理完整ApiResult的场景）
export function getData<T>(url: string, params?: any, config?: Partial<RequestConfig>): Promise<T> {
  const fullUrl = buildUrl(url) + (params ? buildQueryString(params) : '');
  return request<T>({
    url: fullUrl,
    method: 'GET',
    returnRaw: false,
    ...config
  });
}

export function postData<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'POST',
    data,
    returnRaw: false,
    ...config
  });
}

export function putData<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'PUT',
    data,
    returnRaw: false,
    ...config
  });
}

export function delData<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<T> {
  return request<T>({
    url: buildUrl(url),
    method: 'DELETE',
    data,
    returnRaw: false,
    ...config
  });
}

// 导出错误类型和错误类，供外部使用
export { ErrorType, RequestError };

// 默认导出
export default {
  request,
  // 主要方法 - 返回完整ApiResult（适配后台生成代码）
  get,
  post,
  put,
  patch,
  del,
  // 便捷方法 - 自动提取data字段
  getData,
  postData,
  putData,
  delData,
  ErrorType,
  RequestError
};
