import { APP_CONFIG } from '@/config';
import { ensureLogin } from '@/utils/auth';
import { HttpMethod, httpRequest, toFormUrlEncoded } from '@/utils/http';
import { authStorage } from '@/utils/storage';

export interface RequestOptions {
	method?: HttpMethod;
	data?: unknown;
	header?: Record<string, string>;
	skipAuth?: boolean;
	skipAutoLogin?: boolean;
}

export class RequestError extends Error {
	constructor(
		message: string,
		public readonly statusCode?: number,
		public readonly data?: unknown
	) {
		super(message);
		this.name = 'RequestError';
	}
}

const objectToQueryString = (data: object = {}) => {
	return Object.entries(data)
		.filter(([, value]) => value !== undefined && value !== null)
		.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
		.join('&');
};

const buildUrl = (endpoint: string) => {
	if (/^https?:\/\//.test(endpoint)) return endpoint;
	return `${APP_CONFIG.API_BASE_URL}/${endpoint.replace(/^\//, '')}`;
};

const isAuthExpired = (statusCode: number, body: any) => {
	const businessCode = Number(body?.code);
	const message = String(body?.msg || '').replace(/\s+/g, '');
	const hasAuthWord = /登录|token|auth|鉴权/i.test(message);
	const hasExpiredWord = /过期|失效|无效|未登录/.test(message);
	const isLegacyExpired500 = businessCode === 500 && (hasAuthWord && hasExpiredWord);
	return statusCode === 401 || statusCode === 402 || businessCode === 401 || businessCode === 402 || isLegacyExpired500;
};

const requestOnce = async <T>(url: string, options: RequestOptions, retried: boolean): Promise<T> => {
	const headers: Record<string, string> = {
		'content-type': 'application/json',
		...options.header
	};

	if (!options.skipAuth) {
		const token = authStorage.getToken();
		if (token) headers.Authorization = `Bearer ${token}`;
	}

	const response = await httpRequest<T>({
		url,
		method: options.method || 'GET',
		data: options.data,
		header: headers
	});

	const body: any = response.data;
	const businessCode = Number(body?.code);
	const businessMsg = String(body?.msg || '');

	if (isAuthExpired(response.statusCode, response.data)) {
		if (!options.skipAutoLogin && !options.skipAuth && !retried) {
			authStorage.clearToken();
			await ensureLogin();
			return requestOnce<T>(url, options, true);
		}

		throw new RequestError('登录状态已失效', response.statusCode, response.data);
	}

	if (response.statusCode < 200 || response.statusCode >= 300) {
		throw new RequestError(`HTTP 请求失败：${response.statusCode}`, response.statusCode, response.data);
	}

	if (businessCode === 500) {
		throw new RequestError(businessMsg || '服务器处理失败', response.statusCode, response.data);
	}

	return response.data;
};

export const request = <T = any>(endpoint: string, options: RequestOptions = {}) => {
	return requestOnce<T>(buildUrl(endpoint), options, false);
};

export const get = <T = any>(endpoint: string, params?: object, options: RequestOptions = {}) => {
	const queryString = params ? `?${objectToQueryString(params)}` : '';
	return request<T>(`${endpoint}${queryString}`, { ...options, method: 'GET' });
};

export const post = <T = any>(endpoint: string, data?: unknown, options: RequestOptions = {}) => {
	return request<T>(endpoint, { ...options, method: 'POST', data });
};

export const postForm = <T = any>(endpoint: string, data?: Record<string, unknown>, options: RequestOptions = {}) => {
	return request<T>(endpoint, {
		...options,
		method: 'POST',
		data: toFormUrlEncoded(data),
		header: {
			...options.header,
			'content-type': 'application/x-www-form-urlencoded'
		}
	});
};

export const put = <T = any>(endpoint: string, data?: unknown, options: RequestOptions = {}) => {
	return request<T>(endpoint, { ...options, method: 'PUT', data });
};

export const del = <T = any>(endpoint: string, data?: unknown, options: RequestOptions = {}) => {
	return request<T>(endpoint, { ...options, method: 'DELETE', data });
};
