import { useCallback, useRef, useState } from 'react';

import { completeChunkUpload, uploadFileChunk } from '../api/imagery';

export type FileUploadStatus = 'idle' | 'uploading' | 'completed' | 'error'

export type UploadingFile = {
  id: string;
  file: File;
  fileName: string;
  progress: number;
  status: FileUploadStatus;
  totalSize: number;
  uploadedSize: number;
  uuid?: string;
}

const CHUNK_SIZE = 10 * 1024 * 1024 // 10MB
const MAX_CONCURRENT_UPLOADS = 3

export const useAerialChunkUpload = () => {
  const [files, setFiles] = useState<UploadingFile[]>([])
  const abortControllersRef = useRef<Map<string, AbortController>>(new Map())

  const updateFileState = useCallback((id: string, updates: Partial<UploadingFile>) => {
    setFiles((prev) => prev.map((f) => f.id === id ? { ...f, ...updates } : f))
  }, [])

  const uploadSingleFile = useCallback(async (uploadFile: UploadingFile) => {
    const { id, file } = uploadFile
    const abortController = new AbortController()
    abortControllersRef.current.set(id, abortController)

    const { signal } = abortController
    const fileSize = file.size
    const fileName = file.name
    const totalChunks = Math.ceil(fileSize / CHUNK_SIZE)

    updateFileState(id, { status: 'uploading', progress: 0 })

    let uuid = ''

    try {
      for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
        if (signal.aborted) {
          return
        }

        const start = chunkIndex * CHUNK_SIZE
        const end = Math.min(start + CHUNK_SIZE, fileSize)
        const chunkFile = file.slice(start, end)

        const response = await uploadFileChunk({
          fileName,
          fileSize,
          chunkIndex,
          chunkTotalIndex: totalChunks - 1,
          chunkFile,
        })

        if (signal.aborted) {
          return
        }

        // 첫 번째 청크 응답에서 uuid 저장
        if (chunkIndex === 0 && response.uuid) {
          uuid = response.uuid
          updateFileState(id, { uuid })
        }

        const progress = Math.round(((chunkIndex + 1) / totalChunks) * 100)
        const uploadedSize = end

        updateFileState(id, {
          progress,
          uploadedSize,
        })
      }

      // 청크 업로드 완료 후 completeChunkUpload 호출
      if (uuid) {
        await completeChunkUpload(uuid)
      }

      updateFileState(id, { status: 'completed', progress: 100 })
    } catch (error) {
      if (!signal.aborted) {
        console.error('Upload error:', error)
        updateFileState(id, { status: 'error' })
      }
    } finally {
      abortControllersRef.current.delete(id)
    }
  }, [updateFileState])

  const addFiles = useCallback((newFiles: File[]) => {
    const uploadFiles: UploadingFile[] = newFiles.map((file) => ({
      id: crypto.randomUUID(),
      file,
      fileName: file.name,
      progress: 0,
      status: 'idle' as FileUploadStatus,
      totalSize: file.size,
      uploadedSize: 0,
    }))

    setFiles((prev) => [...prev, ...uploadFiles])
    return uploadFiles
  }, [])

  const startUpload = useCallback(async (filesToUpload?: UploadingFile[]) => {
    const targetFiles = filesToUpload || files.filter((f) => f.status === 'idle')

    // 병렬 업로드 (최대 MAX_CONCURRENT_UPLOADS개씩)
    for (let i = 0; i < targetFiles.length; i += MAX_CONCURRENT_UPLOADS) {
      const batch = targetFiles.slice(i, i + MAX_CONCURRENT_UPLOADS)
      await Promise.all(batch.map((file) => uploadSingleFile(file)))
    }
  }, [files, uploadSingleFile])

  const removeFile = useCallback((id: string) => {
    // 업로드 중이면 취소
    const controller = abortControllersRef.current.get(id)
    if (controller) {
      controller.abort()
      abortControllersRef.current.delete(id)
    }

    setFiles((prev) => prev.filter((f) => f.id !== id))
  }, [])

  const cancelAllUploads = useCallback(() => {
    abortControllersRef.current.forEach((controller) => controller.abort())
    abortControllersRef.current.clear()
    setFiles([])
  }, [])

  const reset = useCallback(() => {
    cancelAllUploads()
  }, [cancelAllUploads])

  const isUploading = files.some((f) => f.status === 'uploading')
  const isAllCompleted = files.length > 0 && files.every((f) => f.status === 'completed')
  const hasFiles = files.length > 0

  const totalSize = files.reduce((acc, f) => acc + f.totalSize, 0)
  const uploadedSize = files.reduce((acc, f) => acc + f.uploadedSize, 0)
  const overallProgress = totalSize > 0 ? Math.round((uploadedSize / totalSize) * 100) : 0

  return {
    files,
    addFiles,
    startUpload,
    removeFile,
    cancelAllUploads,
    reset,
    isUploading,
    isAllCompleted,
    hasFiles,
    totalSize,
    uploadedSize,
    overallProgress,
  }
}
