import { useState, useCallback } from 'react';
import { useDropzone } from 'react-dropzone';
import { useForm } from 'react-hook-form';
import { Dialog, DialogBody, DialogFooter } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Progress } from '@/components/ui/progress';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Alert } from '@/components/ui/alert';
import { Upload, X, FileAudio, AlertCircle, CheckCircle2, RefreshCw } from 'lucide-react';
import { uploadTrack, type TrackMetadata } from '@/features/tracks/api/trackApi';
import { useQueryClient } from '@tanstack/react-query';
import { LIBRARY_KEYS } from '@/features/library/hooks/useMyTracks';
import { logger } from '@/utils/logger';


export interface UploadModalProps {
  open: boolean;
  onClose: () => void;
}

const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 MB
const ACCEPTED_AUDIO_TYPES = {
  'audio/mpeg': ['.mp3'],
  'audio/wav': ['.wav'],
  'audio/ogg': ['.ogg'],
  'audio/flac': ['.flac'],
  'audio/mp4': ['.m4a'],
  'audio/aac': ['.aac'],
};

type UploadFormData = {
  file: File | null;
  title: string;
  artist: string;
  album: string;
  genre: string;
};

const MAX_RETRY_ATTEMPTS = 3;

export function UploadModal({ open, onClose }: UploadModalProps) {
  const [file, setFile] = useState<File | null>(null);
  const [uploadProgress, setUploadProgress] = useState(0);
  const [isUploading, setIsUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [errorCode, setErrorCode] = useState<string | null>(null);
  const [isRetryable, setIsRetryable] = useState(false);
  const [retryCount, setRetryCount] = useState(0);
  const [success, setSuccess] = useState(false);

  const queryClient = useQueryClient();

  const {
    register,
    handleSubmit,
    setValue,
    getValues,
    formState: { errors },
    reset,
  } = useForm<UploadFormData>({
    defaultValues: {
      file: null,
      title: '',
      artist: '',
      album: '',
      genre: '',
    },
  });

  const onDrop = useCallback(
    (acceptedFiles: File[]) => {
      const selectedFile = acceptedFiles[0];
      if (selectedFile) {
        setFile(selectedFile);
        setError(null);
        setSuccess(false);
        // Mettre à jour le formulaire avec setValue pour que react-hook-form connaisse le fichier
        setValue('file', selectedFile, { shouldValidate: true });
        // Pré-remplir le titre avec le nom du fichier (sans extension)
        const fileNameWithoutExt = selectedFile.name.replace(/\.[^/.]+$/, '');
        // Lecture à la demande avec getValues, pas de re-render
        const currentTitle = getValues('title');
        if (!currentTitle) {
          setValue('title', fileNameWithoutExt, { shouldValidate: true });
        }
      }
    },
    [setValue, getValues],
  );

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    accept: ACCEPTED_AUDIO_TYPES,
    maxSize: MAX_FILE_SIZE,
    multiple: false,
    onError: (err) => {
      setError(`Erreur lors de la sélection du fichier: ${err.message}`);
    },
    onDropRejected: (fileRejections) => {
      const rejection = fileRejections[0];
      if (rejection.errors[0]?.code === 'file-too-large') {
        setError('Le fichier est trop volumineux (max 100 MB)');
      } else if (rejection.errors[0]?.code === 'file-invalid-type') {
        setError('Format de fichier non supporté. Formats acceptés: MP3, WAV, OGG, FLAC, M4A, AAC');
      } else {
        setError(rejection.errors[0]?.message || 'Erreur lors de la sélection du fichier');
      }
    },
  });

  const performUpload = useCallback(
    async (data: UploadFormData, attemptNumber: number = 1) => {
      if (!data.file) {
        setError('Veuillez sélectionner un fichier');
        setErrorCode(null);
        setIsRetryable(false);
        return;
      }

      setIsUploading(true);
      setError(null);
      setErrorCode(null);
      setIsRetryable(false);
      setSuccess(false);
      setUploadProgress(0);

      try {
        const trackMetadata: TrackMetadata = {
          title: data.title || data.file.name.replace(/\.[^/.]+$/, ''),
          artist: data.artist,
          album: data.album,
          genre: data.genre,
          is_public: false,
        };

        await uploadTrack(
          data.file,
          trackMetadata,
          (progress) => {
            setUploadProgress(progress);
          },
        );

        setSuccess(true);
        setUploadProgress(100);
        setRetryCount(0);

        // Invalider les queries pour rafraîchir la liste
        queryClient.invalidateQueries({ queryKey: LIBRARY_KEYS.all });
        queryClient.invalidateQueries({ queryKey: ['tracks'] });

        // Fermer après 1.5 secondes
        setTimeout(() => {
          handleClose();
        }, 1500);
      } catch (err) {
        let errorMessage = "Erreur lors de l'upload";
        let errorCodeValue: string | null = null;
        let retryable = false;

        if (err instanceof Error) {
          errorMessage = err.message;

          // Détecter les erreurs réseau qui sont généralement retryables
          const isNetworkError =
            errorMessage.toLowerCase().includes('network') ||
            errorMessage.toLowerCase().includes('réseau') ||
            errorMessage.toLowerCase().includes('timeout') ||
            errorMessage.toLowerCase().includes('econnaborted') ||
            errorMessage.toLowerCase().includes('etimedout') ||
            errorMessage.toLowerCase().includes('se connecter');

          // Détecter les erreurs serveur qui peuvent être retryables
          const isServerError =
            errorMessage.toLowerCase().includes('serveur') ||
            errorMessage.toLowerCase().includes('server') ||
            errorMessage.toLowerCase().includes('500') ||
            errorMessage.toLowerCase().includes('503') ||
            errorMessage.toLowerCase().includes('502');

          // Les erreurs de validation ne sont pas retryables
          const isValidationError =
            errorMessage.toLowerCase().includes('format') ||
            errorMessage.toLowerCase().includes('taille') ||
            errorMessage.toLowerCase().includes('invalide') ||
            errorMessage.toLowerCase().includes('trop volumineux') ||
            errorMessage.toLowerCase().includes('non supporté') ||
            errorMessage.toLowerCase().includes('400') ||
            errorMessage.toLowerCase().includes('413') ||
            errorMessage.toLowerCase().includes('415');

          if (isNetworkError) {
            errorCodeValue = 'NETWORK';
            retryable = attemptNumber < MAX_RETRY_ATTEMPTS;
          } else if (isServerError) {
            errorCodeValue = 'SERVER';
            retryable = attemptNumber < MAX_RETRY_ATTEMPTS;
          } else if (isValidationError) {
            errorCodeValue = 'VALIDATION';
            retryable = false;
          }
        }

        setError(errorMessage);
        setErrorCode(errorCodeValue);
        setIsRetryable(retryable);
        setUploadProgress(0);
        setRetryCount(attemptNumber);
      } finally {
        setIsUploading(false);
      }
    },
    [queryClient],
  );

  const onSubmit = useCallback(
    async (data: UploadFormData) => {
      await performUpload(data, 1);
    },
    [performUpload],
  );

  const handleRetry = useCallback(() => {
    const formData = getValues();
    const nextAttempt = retryCount + 1;
    performUpload(formData, nextAttempt);
  }, [retryCount, getValues, performUpload]);

  const handleClose = () => {
    if (!isUploading) {
      setFile(null);
      setUploadProgress(0);
      setError(null);
      setErrorCode(null);
      setIsRetryable(false);
      setRetryCount(0);
      setSuccess(false);
      reset();
      onClose();
    }
  };

  const handleRemoveFile = () => {
    setFile(null);
    setError(null);
    setSuccess(false);
    setUploadProgress(0);
    setValue('file', null, { shouldValidate: true });
  };

  return (
    <Dialog open={open} onClose={handleClose} title="Uploader un fichier audio" size="lg">
      <form
        id="upload-track-form"
        onSubmit={handleSubmit(onSubmit, (errors) => {
          logger.warn('Form validation errors:', { errors });
        })}
      >
        <DialogBody>
          <div className="space-y-6">
            {/* Zone de Drag & Drop */}
            {!file ? (
              <div
                {...getRootProps()}
                className={`
                border-2 border-dashed rounded-lg p-12 text-center cursor-pointer
                transition-colors
                ${isDragActive ? 'border-primary bg-primary/5' : 'border-muted-foreground/25'}
                hover:border-primary hover:bg-primary/5
              `}
              >
                <input {...getInputProps()} />
                <FileAudio className="mx-auto h-12 w-12 text-muted-foreground mb-4" />
                <p className="text-lg font-medium mb-2">
                  {isDragActive ? 'Déposez le fichier ici' : 'Glissez-déposez un fichier audio'}
                </p>
                <p className="text-sm text-muted-foreground mb-4">
                  ou cliquez pour sélectionner
                </p>
                <p className="text-xs text-muted-foreground">
                  Formats acceptés: MP3, WAV, OGG, FLAC, M4A, AAC (max 100 MB)
                </p>
              </div>
            ) : (
              <div className="border rounded-lg p-4" data-testid="upload-file-display">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-3">
                    <FileAudio className="h-8 w-8 text-primary" />
                    <div>
                      <p className="font-medium" data-testid="upload-file-name">{file.name}</p>
                      <p className="text-sm text-muted-foreground">
                        {(file.size / 1024 / 1024).toFixed(2)} MB
                      </p>
                    </div>
                  </div>
                  {!isUploading && (
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      onClick={handleRemoveFile}
                      className="h-8 w-8"
                    >
                      <X className="h-4 w-4" />
                    </Button>
                  )}
                </div>
              </div>
            )}

            {/* Progress Bar */}
            {isUploading && (
              <div className="space-y-2">
                <div className="flex items-center justify-between text-sm">
                  <span>Upload en cours...</span>
                  <span>{uploadProgress}%</span>
                </div>
                <Progress value={uploadProgress} />
              </div>
            )}

            {/* Messages d'erreur */}
            {error && (
              <Alert variant="destructive" data-testid="upload-error">
                <div className="flex items-start gap-3">
                  <AlertCircle className="h-4 w-4 mt-0.5 shrink-0" />
                  <div className="flex-1 space-y-2">
                    <div>
                      <p className="font-medium">{error}</p>
                      {errorCode && (
                        <p className="text-xs text-muted-foreground mt-1">
                          Code d'erreur: {errorCode}
                        </p>
                      )}
                      {retryCount > 0 && (
                        <p className="text-xs text-muted-foreground mt-1">
                          Tentative {retryCount}/{MAX_RETRY_ATTEMPTS}
                        </p>
                      )}
                    </div>
                    {isRetryable && (
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        onClick={handleRetry}
                        disabled={isUploading}
                        className="mt-2"
                      >
                        <RefreshCw className="h-4 w-4 mr-2" />
                        Réessayer
                      </Button>
                    )}
                  </div>
                </div>
              </Alert>
            )}

            {/* Message de succès */}
            {success && (
              <Alert className="bg-green-50 border-green-200 text-green-800">
                <CheckCircle2 className="h-4 w-4" />
                <span>Fichier uploadé avec succès !</span>
              </Alert>
            )}

            {/* Formulaire de métadonnées */}
            {file && !isUploading && !success && (
              <div className="space-y-4 border-t pt-4">
                <h3 className="font-medium">Métadonnées (optionnel)</h3>
                <div className="grid grid-cols-2 gap-4">
                  <div className="space-y-2">
                    <Label htmlFor="title">Titre *</Label>
                    <Input
                      id="title"
                      {...register('title')}
                      placeholder="Titre du morceau"
                    />
                    {errors.title && (
                      <p className="text-sm text-destructive">{errors.title.message}</p>
                    )}
                  </div>
                  <div className="space-y-2">
                    <Label htmlFor="artist">Artiste</Label>
                    <Input
                      id="artist"
                      {...register('artist')}
                      placeholder="Nom de l'artiste"
                    />
                  </div>
                  <div className="space-y-2">
                    <Label htmlFor="album">Album</Label>
                    <Input
                      id="album"
                      {...register('album')}
                      placeholder="Nom de l'album"
                    />
                  </div>
                  <div className="space-y-2">
                    <Label htmlFor="genre">Genre</Label>
                    <Input
                      id="genre"
                      {...register('genre')}
                      placeholder="Genre musical"
                    />
                  </div>
                </div>
              </div>
            )}
          </div>
        </DialogBody>
        <DialogFooter>
          <Button variant="outline" onClick={handleClose} disabled={isUploading} type="button">
            {success ? 'Fermer' : 'Annuler'}
          </Button>
          {!success && (
            <Button
              type="submit"
              form="upload-track-form"
              disabled={!file || isUploading}
              className="gap-2"
            >
              <Upload className="h-4 w-4" />
              {isUploading ? 'Upload en cours...' : 'Uploader'}
            </Button>
          )}
        </DialogFooter>
      </form>
    </Dialog >
  );
}
