import { useState, useEffect, useCallback } from 'react';
import { ChevronLeft, ChevronRight, Download, ExternalLink } from 'lucide-react';
import { Button, Dialog, DialogContent, DialogDescription, DialogTitle } from '@insforge/ui';
import { LoadingState, TypeBadge } from '#components';
import { useStorageObjects } from '#features/storage/hooks/useStorageObjects';
import { StorageFileSchema } from '@insforge/shared-schemas';

interface FilePreviewDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  file: StorageFileSchema | null;
  bucket: string;
  onPrevious?: () => void;
  onNext?: () => void;
  hasPrevious?: boolean;
  hasNext?: boolean;
}

export function FilePreviewDialog({
  open,
  onOpenChange,
  file,
  bucket,
  onPrevious,
  onNext,
  hasPrevious = false,
  hasNext = false,
}: FilePreviewDialogProps) {
  const [isLoading, setIsLoading] = useState(false);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  const { downloadObject } = useStorageObjects();

  // Reset state when file changes
  useEffect(() => {
    if (!file || !open) {
      setPreviewUrl(null);
      setError(null);
      return;
    }

    let currentUrl: string | null = null;

    const loadPreview = async () => {
      if (!file) {
        return;
      }

      setIsLoading(true);
      setError(null);

      try {
        const fileBucket = file.bucket || bucket;
        // Fetch file with authentication and create blob URL
        const blob = await downloadObject(fileBucket, file.key);
        const url = URL.createObjectURL(blob);
        currentUrl = url;
        setPreviewUrl(url);
      } catch (err) {
        const errorMessage = err instanceof Error ? err.message : 'Failed to load preview';
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };

    void loadPreview();

    // Cleanup: Revoke blob URL when component unmounts or file changes
    return () => {
      if (currentUrl) {
        URL.revokeObjectURL(currentUrl);
      }
    };
  }, [file, open, bucket, downloadObject]);

  const handleDownload = () => {
    if (!file || !previewUrl) {
      return;
    }

    try {
      const fileName = file.key.split('/').pop() || file.key;
      const a = document.createElement('a');
      a.href = previewUrl;
      a.download = fileName;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    } catch {
      setError('Download failed');
    }
  };

  const openInNewTab = () => {
    if (previewUrl) {
      window.open(previewUrl, '_blank');
    }
  };

  const handleKeyDown = useCallback(
    (e: KeyboardEvent) => {
      const target = e.target;
      if (
        target instanceof Element &&
        target.closest('input, textarea, select, button, video, audio, iframe, [contenteditable]')
      ) {
        return;
      }
      if (e.key === 'ArrowLeft' && hasPrevious && onPrevious) {
        e.preventDefault();
        onPrevious();
      } else if (e.key === 'ArrowRight' && hasNext && onNext) {
        e.preventDefault();
        onNext();
      }
    },
    [hasPrevious, hasNext, onPrevious, onNext]
  );

  useEffect(() => {
    if (open) {
      window.addEventListener('keydown', handleKeyDown);
      return () => window.removeEventListener('keydown', handleKeyDown);
    }
  }, [open, handleKeyDown]);

  const isPreviewable = (mimeType?: string): boolean => {
    if (!mimeType) {
      return false;
    }
    return (
      mimeType.startsWith('image/') ||
      mimeType.startsWith('video/') ||
      mimeType.startsWith('audio/') ||
      mimeType.startsWith('text/') ||
      mimeType === 'application/json' ||
      mimeType === 'application/pdf'
    );
  };

  const formatFileSize = (bytes: number) => {
    if (bytes < 1024) {
      return `${bytes} B`;
    }
    if (bytes < 1024 * 1024) {
      return `${(bytes / 1024).toFixed(2)} KB`;
    }
    if (bytes < 1024 * 1024 * 1024) {
      return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
    }
    return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
  };

  const renderPreview = () => {
    if (!file) {
      return null;
    }

    // Show empty preview template for non-previewable files or errors
    if (!isPreviewable(file.mimeType) || error || !previewUrl) {
      return <div className="bg-neutral-200 dark:bg-neutral-700 w-full h-full rounded" />;
    }

    const mimeType = file.mimeType || '';
    const fileName = file.key.split('/').pop() || file.key;

    if (mimeType.startsWith('image/')) {
      return (
        <div className="w-full h-full flex items-center justify-center">
          <img
            src={previewUrl}
            alt={fileName}
            className="max-w-full max-h-full object-contain"
            onError={() => setError('Failed to load image')}
          />
        </div>
      );
    }

    if (mimeType.startsWith('video/')) {
      return (
        <video
          src={previewUrl}
          controls
          className="w-full h-full object-contain"
          onError={() => setError('Failed to load video')}
        >
          Your browser does not support the video tag.
        </video>
      );
    }

    if (mimeType.startsWith('audio/')) {
      return (
        <div className="flex items-center justify-center w-full h-full bg-gray-200 dark:bg-transparent">
          <audio
            src={previewUrl}
            controls
            className="w-full max-w-md"
            onError={() => setError('Failed to load audio')}
          >
            Your browser does not support the audio tag.
          </audio>
        </div>
      );
    }

    if (mimeType.startsWith('text/') || mimeType === 'application/json') {
      return <TextPreview url={previewUrl} />;
    }

    if (mimeType === 'application/pdf') {
      return (
        <div className="w-full h-full min-h-0 overflow-hidden">
          <iframe
            src={`${previewUrl}#toolbar=0&navpanes=0`}
            className="w-full h-full"
            title={fileName}
            onError={() => setError('Failed to load PDF')}
          />
        </div>
      );
    }

    // Fallback empty preview
    return (
      <div className="bg-neutral-200 dark:bg-neutral-700 w-full h-full min-h-[400px] rounded" />
    );
  };

  if (!file) {
    return null;
  }

  const fileName = file.key.split('/').pop() || file.key;

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="p-0 w-[800px] max-w-[calc(100vw-2rem)] h-[min(820px,calc(100vh-2rem))] max-h-[calc(100vh-2rem)]">
        <DialogTitle className="sr-only">{fileName}</DialogTitle>
        <DialogDescription className="sr-only">Preview of {fileName}</DialogDescription>
        <div className="w-full h-full flex flex-col bg-white dark:bg-neutral-800">
          {/* Header */}
          <div className="px-6 py-3">
            <div className="flex flex-col items-start gap-1">
              <h2 className="text-lg font-semibold text-zinc-950 dark:text-white truncate">
                {fileName}
              </h2>
              <div className="flex items-center gap-1.5">
                <span className="text-xs font-medium text-zinc-500 dark:text-neutral-400">
                  {formatFileSize(file.size)}
                </span>
                {file.mimeType && (
                  <TypeBadge type={file.mimeType} className="dark:bg-neutral-700" />
                )}
              </div>
            </div>
          </div>

          {/* Preview Content */}
          <div className="relative flex flex-1 min-h-0 overflow-hidden border-y border-zinc-200 dark:border-neutral-600">
            <div className="flex flex-1 p-6">
              {isLoading ? (
                <div className="flex items-center justify-center w-full h-full min-h-0">
                  <LoadingState />
                </div>
              ) : error ? (
                <div
                  className="flex w-full h-full items-center justify-center rounded bg-neutral-100 dark:bg-neutral-700 px-4 text-center"
                  role="alert"
                  aria-live="polite"
                >
                  <p className="text-sm text-zinc-600 dark:text-neutral-200">{error}</p>
                </div>
              ) : (
                renderPreview()
              )}
            </div>
            {(onPrevious || onNext) && (
              <>
                <Button
                  variant="ghost"
                  size="icon"
                  className="absolute left-2 top-1/2 -translate-y-1/2 h-10 w-10 rounded-full bg-black/40 text-white hover:bg-black/60 hover:text-white disabled:opacity-0"
                  onClick={onPrevious}
                  disabled={!hasPrevious}
                  aria-label="Previous file"
                >
                  <ChevronLeft className="h-6 w-6" />
                </Button>
                <Button
                  variant="ghost"
                  size="icon"
                  className="absolute right-2 top-1/2 -translate-y-1/2 h-10 w-10 rounded-full bg-black/40 text-white hover:bg-black/60 hover:text-white disabled:opacity-0"
                  onClick={onNext}
                  disabled={!hasNext}
                  aria-label="Next file"
                >
                  <ChevronRight className="h-6 w-6" />
                </Button>
              </>
            )}
          </div>

          {/* Footer Actions */}
          <div className="px-6 py-6">
            <div className="flex flex-wrap justify-end gap-3">
              <Button
                variant="outline"
                className="flex-1 min-w-[160px] h-10 px-3 gap-1.5 dark:bg-neutral-600 dark:text-zinc-300 dark:border-neutral-600 dark:hover:bg-neutral-700"
                onClick={handleDownload}
              >
                <Download className="h-5 w-5" />
                <span className="text-sm font-medium dark:text-white">Download</span>
              </Button>
              <Button
                variant="outline"
                className="flex-1 min-w-[160px] h-10 px-3 gap-1.5 dark:bg-neutral-600 dark:text-zinc-300 dark:border-neutral-600 dark:hover:bg-neutral-700"
                onClick={openInNewTab}
              >
                <ExternalLink className="h-5 w-5" />
                <span className="text-sm font-medium dark:text-white">Open in new tab</span>
              </Button>
            </div>
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}

// Text file preview component
function TextPreview({ url }: { url: string }) {
  const [content, setContent] = useState<string>('');
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const loadTextContent = async () => {
      try {
        setLoading(true);
        // Fetch the blob URL (which is already authenticated)
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Failed to load text content');
        }

        const text = await response.text();
        // Limit content length for performance
        if (text.length > 100000) {
          setContent(text.substring(0, 100000) + '\n\n... (content truncated due to size)');
        } else {
          setContent(text);
        }
      } catch {
        setContent('Failed to load text content');
      } finally {
        setLoading(false);
      }
    };
    void loadTextContent();
  }, [url]);

  if (loading) {
    return (
      <div className="flex items-center justify-center h-full w-full min-h-[400px]">
        <LoadingState />
      </div>
    );
  }

  return (
    <div className="bg-neutral-50 dark:bg-neutral-800 dark:text-neutral-300 rounded p-4 w-full h-full overflow-auto">
      <pre className="text-sm whitespace-pre-wrap break-words">{content}</pre>
    </div>
  );
}
