import { REQUEST_BASE_URL } from '@/env';
import {
  type AnyRespSchema,
  type AnySucceedResp,
  type ErrorResp,
  type SucceedRespOf,
} from '@/schemas/response';
import { useUserStore } from '@/stores/user';
import type { ComparablePrimitive } from '@/utils/types';
import axios, { type AxiosError, type AxiosRequestConfig } from 'axios';
import { ElMessage } from 'element-plus';
import type { z } from 'zod';
export * from './request';
export const axiosInstance = axios.create({
  baseURL: REQUEST_BASE_URL,
});
export type ValidationErrorCallback = (resp: ErrorResp) => boolean | void;
declare module 'axios' {
  interface AxiosRequestConfig {
    addAuth?: boolean;
    errorDescription?: string;
    onValidationError?: ValidationErrorCallback;
  }
}
// 自动添加token到请求中.
axiosInstance.interceptors.request.use((config) => {
  const userStore = useUserStore();
  if (config.addAuth === undefined || config.addAuth) {
    config.headers.setAuthorization(userStore.token, false);
  }
  return config;
});
// 自动获取响应中的token.
axiosInstance.interceptors.response.use((response) => {
  const userStore = useUserStore();
  const authorization = response.headers['add-authorization'] as string | undefined;
  if (authorization) {
    console.log(123);
    userStore.token = authorization;
  }
  return response;
});
export type RawResp = Record<string, unknown>;
const errorMessage = (
  description: string = '请求错误',
  code: string | number | undefined,
  msg: string,
) => `${description}：(${code})${msg}`;

export const requestRaw = <T = RawResp>(options: AxiosRequestConfig = {}) =>
  axiosInstance
    .request<T>(options)
    .then((r) => r.data)
    .catch((err: AxiosError): undefined => {
      ElMessage.error(errorMessage(options.errorDescription, err.code, err.message));
    });
export function parseRawResp<T extends AnyRespSchema>(
  schema: T,
  raw: RawResp | undefined,
  errorDescription: string | undefined,
  errorCB: ValidationErrorCallback | undefined,
): SucceedRespOf<z.infer<T>> | undefined {
  if (!raw) return;
  const resp = schema.parse(raw);
  if (resp.type === 'error') {
    if (!errorCB?.(resp)) {
      ElMessage.error(errorMessage(errorDescription, resp.status, resp.msg));
    }
    return;
  }
  return resp as any;
}
export async function request<T extends AnyRespSchema>(
  schema: T,
  options: AxiosRequestConfig = {},
) {
  return parseRawResp(
    schema,
    await requestRaw(options),
    options.errorDescription,
    options.onValidationError,
  );
}
export async function patchRequest<T extends Record<string, ComparablePrimitive>>(
  obj: T,
  old: NoInfer<T>,
  mapping: {
    [P in keyof T]?: (v: T[P]) => Promise<AnySucceedResp | boolean | undefined>;
  },
) {
  let changed = false,
    succeed = true;
  let k: keyof T;
  const promises: Promise<unknown>[] = [];
  for (k in obj) {
    const v = obj[k];
    if (v === old[k] || mapping[k]) continue;
    changed = true;
    const p = mapping[k]!(v);
    if (!p) continue;
    promises.push(
      p.then((resp) => {
        if (!resp) succeed = false;
      }),
    );
  }
  await Promise.all(promises);
  const res = !changed ? 'unchanged' : succeed ? 'succeed' : 'error';
  if (res === 'unchanged') {
    ElMessage.info('没有要修改的信息');
  }
  return res;
}
