/**
 * API 配置管理
 *
 * 通过环境变量配置后端服务地址与超时时间。
 * 
 */
import { z } from "zod";

import { AppEnvUtil, type AppEnv } from "@/utils/app-env";

export type { AppEnv };

export interface ApiConfig {
  /** 后端 API 基础 URL（含协议） */
  baseUrl: string;
  /** WebSocket 基础 URL */
  wsUrl: string;
  /** 连接超时（ms） */
  connectTimeout: number;
  /** 接收超时（ms） */
  receiveTimeout: number;
  /** 发送超时（ms） */
  sendTimeout: number;
}

/**
 * 超时常量
 */
export class TimeoutConstants {
  private constructor() {}
  static readonly shortTimeout = 30000;
  static readonly longTimeout = 60000;
}

const DEVELOPMENT_API_BASE_URL = "http://172.16.48.49:3002";
const DEVELOPMENT_WS_BASE_URL = "ws://172.16.48.49:3002/ws";

const ApiConfigSchema = z.object({
  baseUrl: z
    .string()
    .trim()
    .min(1)
    .refine((value) => hasProtocol(value, ["http:", "https:"]), {
      message: "must be an http(s) URL",
    }),
  wsUrl: z
    .string()
    .trim()
    .min(1)
    .refine((value) => hasProtocol(value, ["ws:", "wss:"]), {
      message: "must be a ws(s) URL",
    }),
  connectTimeout: z.coerce.number().int().positive(),
  receiveTimeout: z.coerce.number().int().positive(),
  sendTimeout: z.coerce.number().int().positive(),
});

/**
 * 解析当前环境
 */
export function getAppEnv(): AppEnv {
  return AppEnvUtil.current;
}

/**
 * 获取当前 API 配置
 */
export function getApiConfig(): ApiConfig {
  const appEnv = getAppEnv();
  const allowDevelopmentDefaults = appEnv === "development";
  const result = ApiConfigSchema.safeParse({
    baseUrl:
      process.env.NEXT_PUBLIC_API_BASE_URL ??
      (allowDevelopmentDefaults ? DEVELOPMENT_API_BASE_URL : undefined),
    wsUrl:
      process.env.NEXT_PUBLIC_WS_BASE_URL ??
      (allowDevelopmentDefaults ? DEVELOPMENT_WS_BASE_URL : undefined),
    connectTimeout:
      process.env.NEXT_PUBLIC_API_CONNECT_TIMEOUT ??
      TimeoutConstants.shortTimeout,
    receiveTimeout:
      process.env.NEXT_PUBLIC_API_RECEIVE_TIMEOUT ??
      TimeoutConstants.longTimeout,
    sendTimeout:
      process.env.NEXT_PUBLIC_API_SEND_TIMEOUT ??
      TimeoutConstants.shortTimeout,
  });

  if (!result.success) {
    const issues = result.error.issues
      .map((issue) => `${issue.path.join(".")}: ${issue.message}`)
      .join("; ");
    throw new Error(`[ApiConfig] Invalid ${appEnv} configuration: ${issues}`);
  }

  return result.data;
}

function hasProtocol(value: string, protocols: readonly string[]): boolean {
  try {
    return protocols.includes(new URL(value).protocol);
  } catch {
    return false;
  }
}
