/**
 * 鉴权相关：登录、刷新令牌、本地会话读写。
 *
 * 会话默认存 `localStorage`，键名见下方常量（与 `http.ts` 里读取的 `accessToken` 一致）。
 */
import { postJson } from "./http";
import { ApiPath } from "./paths";

/** localStorage：访问令牌 */
export const ACCESS_TOKEN_KEY = "accessToken";
/** localStorage：刷新令牌 */
export const REFRESH_TOKEN_KEY = "refreshToken";
/** localStorage：用户信息 JSON 字符串 */
export const USER_KEY = "user";

export type AuthUser = Record<string, unknown>;

/** `ClientAuthUserDto`（与 OpenAPI 一致） */
export type ClientAuthUserDto = {
  id: string;
  phone: string;
  nickname: string;
  avatarUrl: string;
};

/** 发送短信验证码时 `scene` 取值（与后端约定一致） */
export const AUTH_SMS_SCENE_LOGIN = "login";

/** `ClientSendSmsResponseDto` */
export type SmsSendResponse = {
  requestId: string;
  phone: string;
  scene: string;
  provider: string;
  expireIn: number;
  testCode?: string;
};

/** `ClientLoginResponseDto` */
export type SmsLoginResponse = {
  accessToken: string;
  refreshToken: string;
  user: ClientAuthUserDto;
};

/** `POST .../auth/refresh` 成功响应 */
export type RefreshTokenResponse = {
  accessToken: string;
  refreshToken: string;
};

/** 写入一对令牌，并清理历史 mock 键 `token` */
export function persistTokens(accessToken: string, refreshToken: string): void {
  window.localStorage.setItem(ACCESS_TOKEN_KEY, accessToken);
  window.localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
  window.localStorage.removeItem("token");
}

/** 写入用户信息（可选） */
export function persistUser(user: AuthUser | undefined): void {
  if (!user) return;
  window.localStorage.setItem(USER_KEY, JSON.stringify(user));
  window.dispatchEvent(new CustomEvent("chatone-user-changed"));
}

/** 清除本地会话（含兼容旧键） */
export function clearSession(): void {
  window.localStorage.removeItem(ACCESS_TOKEN_KEY);
  window.localStorage.removeItem(REFRESH_TOKEN_KEY);
  window.localStorage.removeItem(USER_KEY);
  window.localStorage.removeItem("token");
  window.dispatchEvent(new CustomEvent("chatone-user-changed"));
}

/**
 * 续签失败、双 token 均失效等场景：清会话并回到登录页（整页跳转，避免残留状态）。
 */
export class SessionExpiredError extends Error {
  override readonly name = "SessionExpiredError";
  constructor(message = "登录已过期，请重新登录") {
    super(message);
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

export function invalidateSessionAndGoLogin(): void {
  clearSession();
  const base = import.meta.env.BASE_URL || "/";
  const loginPath = base === "/" ? "/login" : `${String(base).replace(/\/$/, "")}/login`;
  window.location.replace(loginPath);
}

/**
 * 退出登录：尽量通知后端吊销 refresh（失败则忽略），并清除本地会话。
 */
export async function logout(): Promise<void> {
  const refreshToken = window.localStorage.getItem(REFRESH_TOKEN_KEY);
  if (refreshToken) {
    try {
      await postJson<unknown>(ApiPath.authLogout, { refreshToken });
    } catch {
      // 无网或接口未实现时仍允许用户本地退出
    }
  }
  clearSession();
}

/**
 * 发送短信验证码（如登录前获取验证码）。
 * @param phone 国际格式，如 `+86153xxxxxxxx`
 * @param scene 业务场景，默认 `AUTH_SMS_SCENE_LOGIN`
 * @returns `testCode` 仅部分环境返回，用于联调自动填码
 */
export async function sendAuthSmsCode(
  phone: string,
  scene: string = AUTH_SMS_SCENE_LOGIN,
): Promise<{ testCode?: string }> {
  const raw = await postJson<SmsSendResponse>(ApiPath.authSmsSend, { phone, scene });
  const testCode = raw.testCode;
  if (typeof testCode === "string" && testCode.trim()) {
    return { testCode: testCode.trim() };
  }
  return {};
}

/**
 * 短信验证码登录。
 * @param phone 国际格式，如 `+86153xxxxxxxx`
 * @param code 短信验证码
 */
export async function smsLogin(phone: string, code: string): Promise<SmsLoginResponse> {
  return postJson<SmsLoginResponse>(ApiPath.authSmsLogin, { phone, code });
}

/**
 * 使用 refreshToken 换取新的访问令牌与刷新令牌。
 * 该请求在 `http` 层不会附带旧的 `Authorization`。
 */
export async function refreshTokens(refreshToken: string): Promise<RefreshTokenResponse> {
  return postJson<RefreshTokenResponse>(ApiPath.authRefresh, { refreshToken });
}
