export interface AuthUser {
  id?: string | number
  username?: string
  nickname?: string
}

export interface AuthSessionInput {
  token: string
  tokenType?: string
  refreshToken?: string
}

export interface AuthResult {
  token: string
  tokenType?: string
  refreshToken?: string
  expiresIn?: number
  user?: AuthUser
}

interface ApiErrorPayload {
  message?: string
  error?: string
}

const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? '').trim().replace(/\/$/, '')
const LOGIN_PATH = import.meta.env.VITE_LOGIN_PATH ?? '/api/v1/auth/login'
const REGISTER_PATH = import.meta.env.VITE_REGISTER_PATH ?? '/api/v1/auth/register'
const REFRESH_PATH = import.meta.env.VITE_REFRESH_PATH ?? '/api/v1/auth/refresh'
const LOGIN_BEARER_TOKEN = (import.meta.env.VITE_LOGIN_BEARER_TOKEN ?? '').trim()

function buildUrl(path: string): string {
  if (/^https?:\/\//.test(path)) {
    return path
  }

  const normalizedPath = path.startsWith('/') ? path : `/${path}`
  if (!API_BASE_URL) {
    return normalizedPath
  }

  if (API_BASE_URL.startsWith('/')) {
    const basePath = API_BASE_URL.startsWith('/') ? API_BASE_URL : `/${API_BASE_URL}`
    if (normalizedPath === basePath || normalizedPath.startsWith(`${basePath}/`)) {
      return normalizedPath
    }

    return `${basePath}${normalizedPath}`
  }

  // Avoid duplicated API prefix, e.g. base: /api/v1 + path: /api/v1/auth/login
  try {
    const baseUrl = new URL(API_BASE_URL)
    const basePath = baseUrl.pathname.replace(/\/$/, '')
    if (basePath && normalizedPath.startsWith(`${basePath}/`)) {
      return `${API_BASE_URL}${normalizedPath.slice(basePath.length)}`
    }
  } catch {
    // API_BASE_URL may be a relative path; fallback to direct join.
  }

  return `${API_BASE_URL}${normalizedPath}`
}

async function request<T>(
  url: string,
  body: Record<string, unknown>,
  extraHeaders?: Record<string, string>,
): Promise<T> {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...extraHeaders,
    },
    body: JSON.stringify(body),
  })

  const payload = (await response.json().catch(() => ({}))) as T & ApiErrorPayload
  if (!response.ok) {
    throw new Error(payload.message ?? payload.error ?? '请求失败，请稍后再试')
  }

  return payload
}

function createAuthHeader(token: string, tokenType = 'Bearer'): string {
  const normalizedToken = token.trim()
  if (/^\S+\s+\S+/.test(normalizedToken)) {
    return normalizedToken
  }

  return `${tokenType || 'Bearer'} ${normalizedToken}`
}

function extractToken(payload: Record<string, unknown>): string {
  const candidate =
    payload.token ??
    payload.accessToken ??
    payload.access_token ??
    (payload.data as Record<string, unknown> | undefined)?.token ??
    (payload.data as Record<string, unknown> | undefined)?.accessToken ??
    (payload.data as Record<string, unknown> | undefined)?.access_token

  if (typeof candidate !== 'string' || candidate.length === 0) {
    throw new Error('登录成功，但后端未返回 token 字段')
  }

  return candidate
}

function extractTokenType(payload: Record<string, unknown>): string | undefined {
  const candidate =
    payload.token_type ??
    payload.tokenType ??
    (payload.data as Record<string, unknown> | undefined)?.token_type ??
    (payload.data as Record<string, unknown> | undefined)?.tokenType

  return typeof candidate === 'string' && candidate.length > 0 ? candidate : undefined
}

function extractRefreshToken(payload: Record<string, unknown>): string | undefined {
  const candidate =
    payload.refresh_token ??
    payload.refreshToken ??
    (payload.data as Record<string, unknown> | undefined)?.refresh_token ??
    (payload.data as Record<string, unknown> | undefined)?.refreshToken

  return typeof candidate === 'string' && candidate.length > 0 ? candidate : undefined
}

function extractExpiresIn(payload: Record<string, unknown>): number | undefined {
  const candidate =
    payload.expires_in ??
    payload.expiresIn ??
    (payload.data as Record<string, unknown> | undefined)?.expires_in ??
    (payload.data as Record<string, unknown> | undefined)?.expiresIn

  return typeof candidate === 'number' && Number.isFinite(candidate) ? candidate : undefined
}

function extractUser(payload: Record<string, unknown>): AuthUser | undefined {
  const user = payload.user ?? (payload.data as Record<string, unknown> | undefined)?.user
  return typeof user === 'object' && user !== null ? (user as AuthUser) : undefined
}

function parseAuthResult(payload: Record<string, unknown>): AuthResult {
  return {
    token: extractToken(payload),
    tokenType: extractTokenType(payload),
    refreshToken: extractRefreshToken(payload),
    expiresIn: extractExpiresIn(payload),
    user: extractUser(payload),
  }
}

export async function register(input: {
  username: string
  phone: string
  email: string
  password: string
}): Promise<void> {
  await request<Record<string, unknown>>(buildUrl(REGISTER_PATH), input)
}

export async function login(input: { loginId: string; password: string }): Promise<AuthResult> {
  const payload = await request<Record<string, unknown>>(
    buildUrl(LOGIN_PATH),
    {
      login_id: input.loginId,
      password: input.password,
    },
    LOGIN_BEARER_TOKEN ? { Authorization: `Bearer ${LOGIN_BEARER_TOKEN}` } : undefined,
  )
  return parseAuthResult(payload)
}

export async function refreshAccessToken(input: AuthSessionInput): Promise<AuthResult> {
  if (!input.refreshToken) {
    throw new Error('缺少 refresh_token，无法刷新登录状态')
  }

  const payload = await request<Record<string, unknown>>(
    buildUrl(REFRESH_PATH),
    {
      refreshToken: input.refreshToken,
    },
    {
      Authorization: createAuthHeader(input.token, input.tokenType),
    },
  )

  return parseAuthResult(payload)
}
