import { useState, useCallback } from 'react';

export interface UploadProgress {
  loaded: number;
  total: number;
  percent: number;
}

export interface UploadResult {
  url: string;
  path: string;
}

export interface UseMediaUploadConfig {
  /** Base URL for the API (e.g., "" or "http://localhost:8001") */
  apiPrefix?: string;
  /** Service name for API path (e.g., "example-api") */
  serviceName: string;
  /** Auth headers to include in API calls */
  headers?: Record<string, string>;
  /** Called on progress updates during the upload to GCS */
  onProgress?: (progress: UploadProgress) => void;
}

export interface UseMediaUploadResult {
  /** Upload a file. Returns the final URL on success. */
  upload: (file: File) => Promise<UploadResult>;
  /** Whether an upload is in progress */
  isUploading: boolean;
  /** Current upload progress (0-100) */
  progress: number;
  /** Error message if upload failed */
  error: string | null;
  /** Reset state */
  reset: () => void;
}

export function useMediaUpload(config: UseMediaUploadConfig): UseMediaUploadResult {
  const [isUploading, setIsUploading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [error, setError] = useState<string | null>(null);

  const reset = useCallback(() => {
    setIsUploading(false);
    setProgress(0);
    setError(null);
  }, []);

  const upload = useCallback(async (file: File): Promise<UploadResult> => {
    setIsUploading(true);
    setProgress(0);
    setError(null);

    try {
      // 1. Get presigned upload URL from backend
      const initRes = await fetch(
        `${config.apiPrefix || ''}/api/${config.serviceName}/media/upload/init`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            ...config.headers,
          },
          body: JSON.stringify({
            filename: file.name,
            contentType: file.type,
          }),
        }
      );

      if (!initRes.ok) {
        throw new Error(`Upload init failed: ${initRes.status}`);
      }

      const { uploadURL, objectPath, headers: uploadHeaders } = await initRes.json();

      // 2. Upload directly to storage using XHR (for progress tracking)
      await new Promise<void>((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('PUT', uploadURL);
        xhr.timeout = 5 * 60 * 1000; // 5 minutes for large uploads

        // Set headers from presigned response
        if (uploadHeaders) {
          Object.entries(uploadHeaders).forEach(([key, value]) => {
            xhr.setRequestHeader(key, value as string);
          });
        }

        xhr.upload.onprogress = (e) => {
          if (e.lengthComputable) {
            const pct = Math.round((e.loaded / e.total) * 100);
            setProgress(pct);
            config.onProgress?.({ loaded: e.loaded, total: e.total, percent: pct });
          }
        };

        xhr.onload = () => {
          if (xhr.status >= 200 && xhr.status < 300) {
            resolve();
          } else {
            reject(new Error(`Upload failed: ${xhr.status}`));
          }
        };

        xhr.onerror = () => reject(new Error('Upload failed: network error'));
        xhr.ontimeout = () => reject(new Error('Upload timed out'));
        xhr.send(file);
      });

      // 3. Confirm upload with backend
      const completeRes = await fetch(
        `${config.apiPrefix || ''}/api/${config.serviceName}/media/upload/complete`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            ...config.headers,
          },
          body: JSON.stringify({ objectPath }),
        }
      );

      if (!completeRes.ok) {
        throw new Error(`Upload complete failed: ${completeRes.status}`);
      }

      const result = await completeRes.json();
      setProgress(100);
      setIsUploading(false);
      return { url: result.url, path: result.path };
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Upload failed';
      setError(msg);
      setIsUploading(false);
      throw err;
    }
  }, [config]);

  return { upload, isUploading, progress, error, reset };
}
