import hookFetch from 'hook-fetch'

// --- 类型定义 (参考 request.ts) ---

export interface BaseResponse {
	code: number
	error?: string
	isAuthorized?: boolean
	isSuccess?: boolean
}

type OmitBaseResponse<T> = Omit<T, keyof BaseResponse>
export type ResponseData<T = any> = BaseResponse & OmitBaseResponse<T>

export interface RetryConfig {
	retries?: number
	retryDelay?: number
	retryCondition?: (error: any) => boolean
}

interface InterceptorsConfig {
	requestInterceptor?: (config: RequestInit & { url: string }) => RequestInit & { url: string }
	responseInterceptor?: (response: any) => any
	responseErrorInterceptor?: (error: any) => Promise<any>
}

// --- 辅助函数 ---

function getAuthToken(): string | null {
	if (typeof window === 'undefined') return null
	const token =
		localStorage.getItem('oauth2token') ||
		document.cookie.match(new RegExp('(^| )' + 'x-sessionId_b' + '=([^;]*)(;|$)'))?.[2]

	if (token) {
		try {
			return JSON.parse(token) || token
		} catch (e) {
			return token
		}
	}
	return null
}

function sleep(ms: number): Promise<void> {
	return new Promise((resolve) => setTimeout(resolve, ms))
}

// --- HookFetchClient 类封装 ---

class HookFetchClient {
	private instance: any // hook-fetch instance
	private interceptors: InterceptorsConfig = {}

	constructor(baseURL: string, timeout: number) {
		this.instance = hookFetch.create({
			baseURL,
			headers: {
				'Content-Type': 'application/json;charset=utf-8'
			},
			timeout
		})
	}

	// 设置拦截器 (模拟 axios 行为)
	public setInterceptors(config: InterceptorsConfig) {
		this.interceptors = config
	}

	/**
	 * 通用请求方法
	 * 参考 request.ts 中的 request 方法实现
	 */
	public async request<T = any>(
		url: string,
		config?: RequestInit & { retry?: RetryConfig; params?: Record<string, any> }
	): Promise<ResponseData<T>> {
		const { retry, params, ...restConfig } = config || {}

		// 默认重试配置
		const retryConfig: RetryConfig = {
			retries: 0,
			retryDelay: 1000,
			retryCondition: (error: any) => {
				// 默认只重试网络错误或5xx服务器错误
				return !error.status || (error.status >= 500 && error.status < 600)
			},
			...retry
		}

		let lastError: any

		// 构建完整 URL (处理 params)
		let finalUrl = url
		if (params) {
			const searchParams = new URLSearchParams(params as any)
			const queryStr = searchParams.toString()
			if (queryStr) {
				finalUrl += (url.includes('?') ? '&' : '?') + queryStr
			}
		}

		for (let attempt = 0; attempt <= retryConfig.retries!; attempt++) {
			try {
				// 1. 请求拦截器逻辑 (注入 Token)
				let requestConfig: RequestInit & { url: string } = {
					...restConfig,
					url: finalUrl
				}

				// 执行自定义请求拦截器或默认逻辑
				if (this.interceptors.requestInterceptor) {
					requestConfig = this.interceptors.requestInterceptor(requestConfig)
				} else {
					// 默认注入 Token
					const token = getAuthToken()
					const headers = new Headers(requestConfig.headers || {})
					if (token) {
						headers.set('Authorization', token)
					}
					requestConfig.headers = headers
				}

				// 2. 发起请求
				// 注意：这里假设 hookFetch 实例调用方式。如果 hookFetch 是标准 fetch 包装，通常直接调用
				// 由于 hookFetch 具体 API 未知，这里假设它支持 .request 或类似 fetch 的调用
				// 如果 hookFetch.create 返回的对象直接可调用，则使用 this.instance(finalUrl, requestConfig)
				// 此处采用较为通用的 fetch 风格调用，请根据实际 hook-fetch 文档调整
				const response = (await this.instance.request)
					? await this.instance.request(requestConfig.url, requestConfig)
					: await fetch(requestConfig.url, requestConfig)

				// 3. 解析响应
				// 假设响应是 JSON
				let data: any
				try {
					data = await response.json()
				} catch (e) {
					data = null
				}

				// 4. 响应拦截器逻辑
				if (this.interceptors.responseInterceptor) {
					data = this.interceptors.responseInterceptor(data)
				} else {
					// 默认处理：会话丢失重定向
					if (data?.code === 9999) {
						if (import.meta.env?.DEV) {
							window.location.href =
								'/Views/Account/Index.html?cb=' + encodeURIComponent(window.location.href)
						} else {
							window.location.href = '/'
						}
						throw new Error('Session expired')
					}
				}

				return data as ResponseData<T>
			} catch (error: any) {
				lastError = error

				// 错误拦截器
				if (this.interceptors.responseErrorInterceptor) {
					// 如果错误拦截器返回了 Promise.resolve，则可能中断重试或改变行为
					// 这里简单处理，继续重试逻辑判断
				}

				// 判断是否重试
				const shouldRetry = attempt < retryConfig.retries! && retryConfig.retryCondition!(error)

				if (!shouldRetry) {
					break
				}

				// 延迟重试
				if (retryConfig.retryDelay! > 0) {
					await sleep(retryConfig.retryDelay!)
				}
			}
		}

		return Promise.reject(lastError)
	}

	/**
	 * GET 请求
	 */
	public get<T = any>(
		url: string,
		config?: RequestInit & { retry?: RetryConfig; params?: Record<string, any> }
	): Promise<ResponseData<T>> {
		return this.request<T>(url, { ...config, method: 'GET' })
	}

	/**
	 * POST 请求
	 */
	public post<T = any>(
		url: string,
		data?: any,
		config?: RequestInit & { retry?: RetryConfig; params?: Record<string, any> }
	): Promise<ResponseData<T>> {
		return this.request<T>(url, {
			...config,
			method: 'POST',
			body: data ? JSON.stringify(data) : undefined
		})
	}

	/**
	 * PUT 请求
	 */
	public put<T = any>(
		url: string,
		data?: any,
		config?: RequestInit & { retry?: RetryConfig; params?: Record<string, any> }
	): Promise<ResponseData<T>> {
		return this.request<T>(url, {
			...config,
			method: 'PUT',
			body: data ? JSON.stringify(data) : undefined
		})
	}

	/**
	 * DELETE 请求
	 */
	public delete<T = any>(
		url: string,
		config?: RequestInit & { retry?: RetryConfig; params?: Record<string, any> }
	): Promise<ResponseData<T>> {
		return this.request<T>(url, { ...config, method: 'DELETE' })
	}

	/**
	 * PATCH 请求
	 */
	public patch<T = any>(
		url: string,
		data?: any,
		config?: RequestInit & { retry?: RetryConfig; params?: Record<string, any> }
	): Promise<ResponseData<T>> {
		return this.request<T>(url, {
			...config,
			method: 'PATCH',
			body: data ? JSON.stringify(data) : undefined
		})
	}
}

// --- 实例化与导出 ---

// 创建单例实例
const httpClient = new HookFetchClient('', 6000)

// 1. 导出 request 函数 (绑定 this 上下文，确保内部能访问到 httpClient 的状态和方法)
// 这与 request.ts 中的 export const request = http.request.bind(http) 保持一致
export const request = httpClient.request.bind(httpClient)

// 2. 默认导出实例对象 (包含 get, post 等方法)
export default httpClient
