import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
import { request } from '../request';
import { clearUserRouteCache } from './route';
import { type ServiceRequestResult, mapServiceResult, normalizeStringId } from './shared';

/** 后端登录返回 */
interface BackendLoginToken {
  userId: number;
  accessToken: string;
  refreshToken: string;
  expiresTime: number;
}

interface BackendUserInfoDTO {
  userId: string | number;
  userName?: string | null;
  nickname?: string | null;
  deptId?: string | number | null;
  roles?: string[] | null;
  buttons?: string[] | null;
}

interface BackendMyProfileDetailDTO {
  id?: string | number | null;
  userId?: string | number | null;
  username?: string | null;
  userName?: string | null;
  nickname?: string | null;
  company?: string | null;
  email?: string | null;
  mobile?: string | null;
  sex?: Api.SystemManage.UserGender | null;
  avatar?: string | null;
  loginIp?: string | null;
  loginDate?: string | null;
  createTime?: string | null;
  roles?: Api.SystemManage.RoleSimple[] | null;
  dept?: Api.SystemManage.DeptSimple | null;
  position?: Api.SystemManage.PostSimple | null;
}

interface BackendFileDTO {
  id: string | number;
  configId: string | number;
  name?: string | null;
  path: string;
  url: string;
}

let userInfoPromise: Promise<ServiceRequestResult<BackendUserInfoDTO>> | null = null;

/** 将后端 token 结构转换成前端现有结构 */
function mapLoginToken(data: BackendLoginToken): Api.Auth.LoginToken {
  return {
    token: data.accessToken,
    refreshToken: data.refreshToken
  };
}

function mapUserInfo(data: BackendUserInfoDTO): Api.Auth.UserInfo {
  return {
    userId: String(data.userId ?? ''),
    userName: data.userName ?? '',
    nickname: data.nickname ?? '',
    deptId: safeStringId(data.deptId),
    roles: data.roles ?? [],
    buttons: data.buttons ?? []
  };
}

function safeStringId(value: string | number | null | undefined): string | null {
  return value === null || value === undefined ? null : String(value);
}

// eslint-disable-next-line complexity
function mapMyProfileDetail(data: BackendMyProfileDetailDTO, fallbackUserId = ''): Api.Auth.MyProfileDetail {
  const baseInfo = {
    userId: String(data.id ?? data.userId ?? fallbackUserId ?? ''),
    username: data.username ?? data.userName ?? '',
    nickname: data.nickname ?? '',
    deptId: safeStringId(data.dept?.id),
    deptName: data.dept?.name ?? '',
    positionId: safeStringId(data.position?.id),
    positionName: data.position?.name ?? ''
  };

  const contactInfo = {
    company: data.company ?? null,
    email: data.email ?? '',
    mobile: data.mobile ?? '',
    sex: data.sex ?? 0,
    avatar: data.avatar ?? ''
  };

  const extraInfo = {
    roles: data.roles ?? [],
    dept: data.dept ?? null,
    position: data.position ?? null,
    loginIp: data.loginIp ?? '',
    loginDate: data.loginDate ?? null,
    createTime: data.createTime ?? null
  };

  return { ...baseInfo, ...contactInfo, ...extraInfo };
}

export function clearUserInfoCache() {
  userInfoPromise = null;
}

export function clearAuthApiCache() {
  clearUserInfoCache();
  clearUserRouteCache();
}

/**
 * 登录
 *
 * @param userName 用户名
 * @param password 密码
 */
export async function fetchLogin(
  userName: string,
  password: string
): Promise<ServiceRequestResult<Api.Auth.LoginToken>> {
  clearAuthApiCache();

  const result = await request<BackendLoginToken>({
    url: `${SYSTEM_SERVICE_PREFIX}/auth/login`,
    method: 'post',
    data: {
      username: userName,
      password,
      rememberMe: true
    }
  });

  if (result.error || !result.data) {
    return result as ServiceRequestResult<Api.Auth.LoginToken>;
  }

  return {
    ...result,
    data: mapLoginToken(result.data)
  };
}

/** 获取用户信息 */
export async function fetchGetUserInfo(force = false): Promise<ServiceRequestResult<Api.Auth.UserInfo>> {
  if (!userInfoPromise || force) {
    userInfoPromise = request<BackendUserInfoDTO>({
      url: `${SYSTEM_SERVICE_PREFIX}/auth/get-user-info`
    }).then(result => result as ServiceRequestResult<BackendUserInfoDTO>);
  }

  const result = await userInfoPromise;

  if (result.error || !result.data) {
    userInfoPromise = null;
    return result as ServiceRequestResult<Api.Auth.UserInfo>;
  }

  return {
    ...result,
    data: mapUserInfo(result.data)
  };
}

/** 获取当前登录人资料详情 */
export async function fetchGetMyProfileDetail(
  options: {
    userId?: string;
  } = {}
): Promise<ServiceRequestResult<Api.Auth.MyProfileDetail>> {
  const result = await request<BackendMyProfileDetailDTO>({
    url: `${SYSTEM_SERVICE_PREFIX}/user/profile/get`,
    method: 'get'
  });

  if (result.error || !result.data) {
    return result as ServiceRequestResult<Api.Auth.MyProfileDetail>;
  }

  return {
    ...result,
    data: mapMyProfileDetail(result.data, options.userId ?? '')
  };
}

/** 更新当前登录人基础资料 */
export function fetchUpdateMyProfile(data: Api.Auth.UpdateMyProfileParams) {
  return request<boolean>({
    url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update`,
    method: 'put',
    data
  });
}

/** 修改当前登录人密码 */
export async function fetchUpdateMyAvatar(file: File) {
  const formData = new FormData();
  formData.append('file', file);

  const result = await request<BackendFileDTO>({
    url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-avatar`,
    method: 'put',
    data: formData
  });

  return mapServiceResult(result as ServiceRequestResult<BackendFileDTO>, data => ({
    ...data,
    id: normalizeStringId(data.id),
    configId: normalizeStringId(data.configId)
  }));
}

export function fetchUpdateMyPassword(data: Api.Auth.UpdateMyPasswordParams) {
  return request<boolean>({
    url: `${SYSTEM_SERVICE_PREFIX}/user/profile/update-password`,
    method: 'put',
    data
  });
}

/**
 * 刷新 token
 *
 * @param refreshToken 刷新 token
 */
export async function fetchRefreshToken(refreshToken: string): Promise<ServiceRequestResult<Api.Auth.LoginToken>> {
  // 后端要求 refreshToken 通过 query 参数传递，且 Content-Type 为 form-urlencoded
  // skipAuth: 不注入过期 access 头，否则会被网关拦下死循环（网关一律校验 Authorization，不看 PermitAll）
  const result = await request<BackendLoginToken>({
    url: `${SYSTEM_SERVICE_PREFIX}/auth/refresh-token`,
    method: 'post',
    params: { refreshToken },
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    skipAuth: true,
    suppressErrorMessage: true,
    skipTokenRefresh: true
  });

  if (result.error || !result.data) {
    return result as ServiceRequestResult<Api.Auth.LoginToken>;
  }

  return {
    ...result,
    data: mapLoginToken(result.data)
  };
}

/**
 * 返回自定义后端错误
 *
 * @param code 错误码
 * @param msg 错误信息
 */
export function fetchCustomBackendError(code: string, msg: string) {
  return request({ url: '/auth/error', params: { code, msg } });
}
