import { API_BASE_URL, AUTH_TOKEN_KEY } from "@/utils/constants";
import type { ApiEnvelope } from "@/types/api";

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

interface RequestOptions<TBody = unknown> {
  method?: HttpMethod;
  data?: TBody;
  header?: Record<string, string>;
  skipAuth?: boolean;
}

export class ApiError extends Error {
  statusCode?: number;
  code?: string;

  constructor(message: string, statusCode?: number, code?: string) {
    super(message);
    this.name = "ApiError";
    this.statusCode = statusCode;
    this.code = code;
  }
}

function getToken() {
  return uni.getStorageSync(AUTH_TOKEN_KEY) as string | undefined;
}

function buildHeaders(options?: RequestOptions) {
  const token = getToken();
  const headers: Record<string, string> = {
    "content-type": "application/json",
    ...(options?.header || {})
  };

  if (token && !options?.skipAuth) {
    headers.Authorization = `Bearer ${token}`;
  }

  return headers;
}

export function request<TResponse, TBody = unknown>(path: string, options: RequestOptions<TBody> = {}) {
  return new Promise<TResponse>((resolve, reject) => {
    uni.request({
      url: `${API_BASE_URL}${path}`,
      method: options.method || "GET",
      data: options.data as UniApp.RequestOptions["data"],
      header: buildHeaders(options),
      success(response) {
        const statusCode = response.statusCode;
        const body = response.data as ApiEnvelope<TResponse> | TResponse;

        if (statusCode >= 200 && statusCode < 300) {
          if (body && typeof body === "object" && "success" in body) {
            const envelope = body as ApiEnvelope<TResponse>;
            if (envelope.success === false) {
              reject(new ApiError(envelope.error?.message || envelope.message || "请求失败", statusCode, envelope.error?.code));
              return;
            }
            resolve((envelope.data ?? (body as TResponse)) as TResponse);
            return;
          }

          resolve(body as TResponse);
          return;
        }

        const envelope = body as ApiEnvelope<TResponse>;
        reject(new ApiError(envelope?.error?.message || envelope?.message || `请求失败 ${statusCode}`, statusCode, envelope?.error?.code));
      },
      fail(error) {
        reject(new ApiError(error.errMsg || "网络连接失败"));
      }
    });
  });
}

export function uploadFile<TResponse>(path: string, filePath: string, formData?: Record<string, string | number | boolean>) {
  return new Promise<TResponse>((resolve, reject) => {
    const token = getToken();
    uni.uploadFile({
      url: `${API_BASE_URL}${path}`,
      filePath,
      name: "file",
      formData,
      header: token ? { Authorization: `Bearer ${token}` } : undefined,
      success(response) {
        const statusCode = response.statusCode;
        let body: ApiEnvelope<TResponse> | TResponse | undefined;

        try {
          body = response.data ? (JSON.parse(response.data) as ApiEnvelope<TResponse> | TResponse) : undefined;
        } catch {
          body = response.data as TResponse;
        }

        if (statusCode >= 200 && statusCode < 300) {
          if (body && typeof body === "object" && "success" in body) {
            const envelope = body as ApiEnvelope<TResponse>;
            if (envelope.success === false) {
              reject(new ApiError(envelope.error?.message || envelope.message || "上传失败", statusCode, envelope.error?.code));
              return;
            }
            resolve((envelope.data ?? body) as TResponse);
            return;
          }

          resolve(body as TResponse);
          return;
        }

        const envelope = body as ApiEnvelope<TResponse>;
        reject(new ApiError(envelope?.error?.message || envelope?.message || `上传失败 ${statusCode}`, statusCode, envelope?.error?.code));
      },
      fail(error) {
        reject(new ApiError(error.errMsg || "上传失败"));
      }
    });
  });
}
