import type {
	ApiError,
	ApiResponse,
	ClearAndResetVideoResponse,
	CollectionsResponse,
	Config,
	DashBoardResponse,
	FavoritesResponse,
	QrcodeGenerateResponse as GenerateQrcodeResponse,
	InsertCollectionRequest,
	InsertFavoriteRequest,
	InsertSubmissionRequest,
	Notifier,
	QrcodePollResponse as PollQrcodeResponse,
	ResetFilteredVideosResponse,
	ResetFilteredVideoStatusRequest,
	ResetVideoResponse,
	ResetVideoStatusRequest,
	SysInfo,
	TaskStatus,
	UpdateFilteredVideoStatusRequest,
	UpdateFilteredVideoStatusResponse,
	UpdateVideoSourceRequest,
	UpdateVideoSourceResponse,
	UpdateVideoStatusRequest,
	UpdateVideoStatusResponse,
	UppersResponse,
	VideoResponse,
	VideoSourcesDetailsResponse,
	VideoSourcesResponse,
	VideosRequest,
	VideosResponse
} from './types';
import { wsManager } from './ws';

// API 基础配置
const API_BASE_URL = '/api';

// HTTP 客户端类
class ApiClient {
	private baseURL: string;
	private defaultHeaders: Record<string, string>;

	constructor(baseURL: string = API_BASE_URL) {
		this.baseURL = baseURL;
		this.defaultHeaders = {
			'Content-Type': 'application/json'
		};
		const token = localStorage.getItem('authToken');
		if (token) {
			this.defaultHeaders['Authorization'] = token;
		}
	}

	// 设置认证 token
	setAuthToken(token?: string) {
		if (token) {
			this.defaultHeaders['Authorization'] = token;
			localStorage.setItem('authToken', token);
		} else {
			delete this.defaultHeaders['Authorization'];
			localStorage.removeItem('authToken');
		}
	}

	getAuthToken(): string | null {
		return this.defaultHeaders['Authorization'] || localStorage.getItem('authToken');
	}

	// 清除认证 token
	clearAuthToken() {
		delete this.defaultHeaders['Authorization'];
		localStorage.removeItem('authToken');
		// 断开 WebSocket 连接，因为 token 已经无效
		wsManager.disconnect();
	}

	// 通用请求方法
	private async request<T>(
		url: string,
		method: string = 'GET',
		body?: unknown,
		params?: Record<string, unknown>
	): Promise<ApiResponse<T>> {
		// 构建完整的 URL
		let fullUrl = `${this.baseURL}${url}`;
		if (params) {
			const searchParams = new URLSearchParams();
			Object.entries(params).forEach(([key, value]) => {
				if (value !== undefined && value !== null) {
					searchParams.append(key, String(value));
				}
			});
			const queryString = searchParams.toString();
			if (queryString) {
				fullUrl += `?${queryString}`;
			}
		}

		const config: RequestInit = {
			method,
			headers: this.defaultHeaders
		};

		if (body && method !== 'GET') {
			config.body = JSON.stringify(body);
		}

		try {
			const response = await fetch(fullUrl, config);

			if (!response.ok) {
				const errorText = await response.text();
				let errorMessage: string;
				try {
					const errorJson = JSON.parse(errorText);
					errorMessage = errorJson.message || errorJson.error || '请求失败';
				} catch {
					errorMessage = errorText || `HTTP ${response.status}: ${response.statusText}`;
				}
				throw {
					message: errorMessage,
					status: response.status
				} as ApiError;
			}

			return await response.json();
		} catch (error) {
			if (error && typeof error === 'object' && 'status' in error) {
				throw error;
			}
			throw {
				message: error instanceof Error ? error.message : '网络请求失败',
				status: 0
			} as ApiError;
		}
	}

	// GET 请求
	private async get<T>(url: string, params?: Record<string, unknown>): Promise<ApiResponse<T>> {
		return this.request<T>(url, 'GET', undefined, params);
	}

	// POST 请求
	private async post<T>(url: string, data?: unknown): Promise<ApiResponse<T>> {
		return this.request<T>(url, 'POST', data);
	}

	// PUT 请求
	private async put<T>(url: string, data?: unknown): Promise<ApiResponse<T>> {
		return this.request<T>(url, 'PUT', data);
	}

	async getVideoSources(): Promise<ApiResponse<VideoSourcesResponse>> {
		return this.get<VideoSourcesResponse>('/video-sources');
	}

	async getVideos(params?: VideosRequest): Promise<ApiResponse<VideosResponse>> {
		return this.get<VideosResponse>('/videos', params as Record<string, unknown>);
	}

	async getVideo(id: number): Promise<ApiResponse<VideoResponse>> {
		return this.get<VideoResponse>(`/videos/${id}`);
	}

	async resetVideoStatus(
		id: number,
		request: ResetVideoStatusRequest
	): Promise<ApiResponse<ResetVideoResponse>> {
		return this.post<ResetVideoResponse>(`/videos/${id}/reset-status`, request);
	}

	async clearAndResetVideoStatus(id: number): Promise<ApiResponse<ClearAndResetVideoResponse>> {
		return this.post<ClearAndResetVideoResponse>(`/videos/${id}/clear-and-reset-status`);
	}

	async resetFilteredVideoStatus(
		request: ResetFilteredVideoStatusRequest
	): Promise<ApiResponse<ResetFilteredVideosResponse>> {
		return this.post<ResetFilteredVideosResponse>('/videos/reset-status', request);
	}

	async updateVideoStatus(
		id: number,
		request: UpdateVideoStatusRequest
	): Promise<ApiResponse<UpdateVideoStatusResponse>> {
		return this.post<UpdateVideoStatusResponse>(`/videos/${id}/update-status`, request);
	}

	async updateFilteredVideoStatus(
		request: UpdateFilteredVideoStatusRequest
	): Promise<ApiResponse<UpdateFilteredVideoStatusResponse>> {
		return this.post<UpdateFilteredVideoStatusResponse>('/videos/update-status', request);
	}

	async getCreatedFavorites(): Promise<ApiResponse<FavoritesResponse>> {
		return this.get<FavoritesResponse>('/me/favorites');
	}

	async getFollowedCollections(
		pageNum?: number,
		pageSize?: number
	): Promise<ApiResponse<CollectionsResponse>> {
		const params = {
			page_num: pageNum,
			page_size: pageSize
		};
		return this.get<CollectionsResponse>('/me/collections', params as Record<string, unknown>);
	}

	async getFollowedUppers(
		pageNum?: number,
		pageSize?: number,
		name?: string
	): Promise<ApiResponse<UppersResponse>> {
		const params = {
			page_num: pageNum,
			page_size: pageSize,
			name: name
		};
		return this.get<UppersResponse>('/me/uppers', params as Record<string, unknown>);
	}

	async insertFavorite(request: InsertFavoriteRequest): Promise<ApiResponse<boolean>> {
		return this.post<boolean>('/video-sources/favorites', request);
	}

	async insertCollection(request: InsertCollectionRequest): Promise<ApiResponse<boolean>> {
		return this.post<boolean>('/video-sources/collections', request);
	}

	async insertSubmission(request: InsertSubmissionRequest): Promise<ApiResponse<boolean>> {
		return this.post<boolean>('/video-sources/submissions', request);
	}

	async getVideoSourcesDetails(): Promise<ApiResponse<VideoSourcesDetailsResponse>> {
		return this.get<VideoSourcesDetailsResponse>('/video-sources/details');
	}

	async updateVideoSource(
		type: string,
		id: number,
		request: UpdateVideoSourceRequest
	): Promise<ApiResponse<UpdateVideoSourceResponse>> {
		return this.put<UpdateVideoSourceResponse>(`/video-sources/${type}/${id}`, request);
	}

	async removeVideoSource(type: string, id: number): Promise<ApiResponse<boolean>> {
		return this.request<boolean>(`/video-sources/${type}/${id}`, 'DELETE');
	}

	async evaluateVideoSourceRules(type: string, id: number): Promise<ApiResponse<boolean>> {
		return this.post<boolean>(`/video-sources/${type}/${id}/evaluate`, null);
	}

	async getDefaultPath(type: string, name: string): Promise<ApiResponse<string>> {
		return this.get<string>(`/video-sources/${type}/default-path`, { name });
	}

	async testNotifier(notifier: Notifier): Promise<ApiResponse<boolean>> {
		return this.post<boolean>('/config/notifiers/ping', notifier);
	}

	async getConfig(): Promise<ApiResponse<Config>> {
		return this.get<Config>('/config');
	}

	async updateConfig(config: Config): Promise<ApiResponse<Config>> {
		return this.put<Config>('/config', config);
	}

	async getDashboard(): Promise<ApiResponse<DashBoardResponse>> {
		return this.get<DashBoardResponse>('/dashboard');
	}

	async triggerDownloadTask(): Promise<ApiResponse<boolean>> {
		return this.post<boolean>('/task/download');
	}

	async generateQrcode(): Promise<ApiResponse<GenerateQrcodeResponse>> {
		return this.post<GenerateQrcodeResponse>('/login/qrcode/generate');
	}

	async pollQrcode(qrcodeKey: string): Promise<ApiResponse<PollQrcodeResponse>> {
		return this.get<PollQrcodeResponse>('/login/qrcode/poll', { qrcode_key: qrcodeKey });
	}

	subscribeToLogs(onMessage: (data: string) => void) {
		return wsManager.subscribeToLogs(onMessage);
	}
	subscribeToSysInfo(onMessage: (data: SysInfo) => void) {
		return wsManager.subscribeToSysInfo(onMessage);
	}
	subscribeToTasks(onMessage: (data: TaskStatus) => void) {
		return wsManager.subscribeToTasks(onMessage);
	}
}

// 创建默认的 API 客户端实例
export const apiClient = new ApiClient();

// 导出 API 方法的便捷函数
const api = {
	getVideoSources: () => apiClient.getVideoSources(),
	getVideos: (params?: VideosRequest) => apiClient.getVideos(params),
	getVideo: (id: number) => apiClient.getVideo(id),
	resetVideoStatus: (id: number, request: ResetVideoStatusRequest) =>
		apiClient.resetVideoStatus(id, request),
	clearAndResetVideoStatus: (id: number) => apiClient.clearAndResetVideoStatus(id),
	resetFilteredVideoStatus: (request: ResetFilteredVideoStatusRequest) =>
		apiClient.resetFilteredVideoStatus(request),
	updateVideoStatus: (id: number, request: UpdateVideoStatusRequest) =>
		apiClient.updateVideoStatus(id, request),
	updateFilteredVideoStatus: (request: UpdateFilteredVideoStatusRequest) =>
		apiClient.updateFilteredVideoStatus(request),
	getCreatedFavorites: () => apiClient.getCreatedFavorites(),
	getFollowedCollections: (pageNum?: number, pageSize?: number) =>
		apiClient.getFollowedCollections(pageNum, pageSize),
	getFollowedUppers: (pageNum?: number, pageSize?: number, name?: string) =>
		apiClient.getFollowedUppers(pageNum, pageSize, name),
	insertFavorite: (request: InsertFavoriteRequest) => apiClient.insertFavorite(request),
	insertCollection: (request: InsertCollectionRequest) => apiClient.insertCollection(request),
	insertSubmission: (request: InsertSubmissionRequest) => apiClient.insertSubmission(request),
	getVideoSourcesDetails: () => apiClient.getVideoSourcesDetails(),
	updateVideoSource: (type: string, id: number, request: UpdateVideoSourceRequest) =>
		apiClient.updateVideoSource(type, id, request),
	removeVideoSource: (type: string, id: number) => apiClient.removeVideoSource(type, id),
	evaluateVideoSourceRules: (type: string, id: number) =>
		apiClient.evaluateVideoSourceRules(type, id),
	getDefaultPath: (type: string, name: string) => apiClient.getDefaultPath(type, name),
	testNotifier: (notifier: Notifier) => apiClient.testNotifier(notifier),
	getConfig: () => apiClient.getConfig(),
	updateConfig: (config: Config) => apiClient.updateConfig(config),
	getDashboard: () => apiClient.getDashboard(),
	triggerDownloadTask: () => apiClient.triggerDownloadTask(),
	generateQrcode: () => apiClient.generateQrcode(),
	pollQrcode: (qrcodeKey: string) => apiClient.pollQrcode(qrcodeKey),
	subscribeToSysInfo: (onMessage: (data: SysInfo) => void) =>
		apiClient.subscribeToSysInfo(onMessage),

	subscribeToLogs: (onMessage: (data: string) => void) => apiClient.subscribeToLogs(onMessage),

	subscribeToTasks: (onMessage: (data: TaskStatus) => void) =>
		apiClient.subscribeToTasks(onMessage),

	setAuthToken: (token: string) => apiClient.setAuthToken(token),
	getAuthToken: () => apiClient.getAuthToken(),
	clearAuthToken: () => apiClient.clearAuthToken()
};

export default api;
