import type { components } from "./__generated__/openapi.types"

import { fetchClient } from "."

import { ACCESS_TOKEN_REGEXP, API_URL } from "@shared/lib/constants"

type FileInfoResponse = components["schemas"]["FileInfoResponse"]
type ProgressCallback = (percent: number) => void

/**
 * Upload a file to the storage API.
 * Handles FormData construction and Content-Type header override
 * required for multipart uploads via openapi-fetch.
 *
 * @param file - File object to upload
 * @param folder - Target folder in storage (default: "")
 * @returns FileInfoResponse with file_path and file_url
 */
export async function uploadFile(
	file: File,
	folder = "",
): Promise<FileInfoResponse> {
	const formData = new FormData()
	formData.append("file", file)
	formData.append("folder", folder)

	const { data, error } = await fetchClient.POST("/api/files/upload/", {
		body: formData as unknown as { file: string; folder: string },
		bodySerializer: () => formData as unknown as string,
		headers: { "Content-Type": null },
	})

	if (error || !data) {
		throw new Error("File upload failed")
	}

	return data
}

/**
 * Upload a file with real-time progress tracking.
 * Uses XMLHttpRequest for access to upload progress events.
 *
 * @param file - File object to upload
 * @param folder - Target folder in storage (default: "")
 * @param onProgress - Callback receiving upload percentage (0–100)
 * @returns FileInfoResponse with file_path and file_url
 */
export function uploadFileWithProgress(
	file: File,
	folder = "",
	onProgress?: ProgressCallback,
): Promise<FileInfoResponse> {
	return new Promise((resolve, reject) => {
		const formData = new FormData()
		formData.append("file", file)
		formData.append("folder", folder)

		const xhr = new XMLHttpRequest()
		xhr.open("POST", `${API_URL}/api/files/upload/`)

		const token = document.cookie.replace(ACCESS_TOKEN_REGEXP, "$1")
		if (token.length) {
			xhr.setRequestHeader("Authorization", `Bearer ${token}`)
		}

		xhr.upload.onprogress = (e) => {
			if (e.lengthComputable && onProgress) {
				onProgress(Math.round((e.loaded / e.total) * 100))
			}
		}

		xhr.onload = () => {
			if (xhr.status >= 200 && xhr.status < 300) {
				try {
					resolve(JSON.parse(xhr.responseText) as FileInfoResponse)
				} catch {
					reject(new Error("Не удалось разобрать ответ сервера"))
				}
			} else {
				reject(new Error("Ошибка загрузки файла"))
			}
		}

		xhr.onerror = () => reject(new Error("Ошибка сети при загрузке"))

		xhr.send(formData)
	})
}
