import { useCallback, useState } from 'react';
import { compressPhoto, formatBytes } from '../lib/image';
import { uploadPhoto, type UploadError } from '../services/photosApi';
import { useGuestIdentity } from '../context/GuestIdentityContext';
import { useGuestTaskProgress } from '../hooks/useGuestTaskProgress';
import { resolveUploadErrorDialog, type UploadErrorDialog } from '../lib/uploadErrorDialog';
import { notify } from '../queue/notify';
import { useTranslation } from '../i18n/useTranslation';
import { isGuestDemoModeEnabled } from '../demo/demoMode';
import { useEventData } from './useEventData';
import { triggerHaptic } from '../lib/haptics';

type DirectUploadResult = {
  success: boolean;
  photoId?: number;
  warning?: string | null;
  error?: string | null;
  dialog?: UploadErrorDialog | null;
};

type UseDirectUploadOptions = {
  eventToken: string;
  taskId?: number | null;
  emotionSlug?: string;
  onCompleted?: (photoId: number) => void;
};

export function useDirectUpload({ eventToken, taskId, emotionSlug, onCompleted }: UseDirectUploadOptions) {
  const { name } = useGuestIdentity();
  const { markCompleted } = useGuestTaskProgress(eventToken);
  const { event } = useEventData();
  const { t } = useTranslation();
  const [uploading, setUploading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [warning, setWarning] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [errorDialog, setErrorDialog] = useState<UploadErrorDialog | null>(null);
  const [canUpload, setCanUpload] = useState(true);

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

  const preparePhoto = useCallback(async (file: File) => {
    reset();
    let prepared = file;
    try {
      prepared = await compressPhoto(file, {
        maxEdge: 2400,
        targetBytes: 4_000_000,
        qualityStart: 0.82,
      });
      if (prepared.size < file.size - 50_000) {
        const saved = formatBytes(file.size - prepared.size);
        setWarning(`Wir haben dein Foto verkleinert, damit der Upload schneller klappt. Eingespart: ${saved}`);
      }
    } catch (err) {
      console.warn('Direct upload: optimization failed, using original', err);
      setWarning('Optimierung nicht möglich – wir laden das Original hoch.');
    }

    if (prepared.size > 12_000_000) {
      setError('Das Foto war zu groß. Bitte erneut versuchen – wir verkleinern es automatisch.');
      return { ok: false as const };
    }

    return { ok: true as const, prepared };
  }, [reset]);

  const upload = useCallback(
    async (file: File): Promise<DirectUploadResult> => {
      if (!canUpload || uploading) return { success: false, warning, error };
      if (isGuestDemoModeEnabled() || event?.demo_read_only) {
        const demoMessage = t('upload.demoReadOnly', 'Uploads sind in der Demo deaktiviert.');
        setError(demoMessage);
        setWarning(null);
        notify(demoMessage, 'error');
        return { success: false, warning, error: demoMessage };
      }
      const preparedResult = await preparePhoto(file);
      if (!preparedResult.ok) {
        return { success: false, warning, error };
      }

      const prepared = preparedResult.prepared;
      setUploading(true);
      setProgress(2);
      setError(null);
      setErrorDialog(null);

      try {
        const photoId = await uploadPhoto(eventToken, prepared, taskId ?? undefined, emotionSlug || undefined, {
          maxRetries: 2,
          guestName: name || undefined,
          onProgress: (percent) => {
            setProgress(Math.max(10, Math.min(98, percent)));
          },
          onRetry: (attempt) => {
            setWarning(`Verbindung holperig – neuer Versuch (${attempt}).`);
          },
        });

        setProgress(100);
        if (taskId) {
          markCompleted(taskId);
        }
        triggerHaptic('success');

        try {
          const raw = localStorage.getItem('my-photo-ids');
          const arr: number[] = raw ? JSON.parse(raw) : [];
          if (photoId && !arr.includes(photoId)) {
            localStorage.setItem('my-photo-ids', JSON.stringify([photoId, ...arr]));
          }
        } catch (persistErr) {
          console.warn('Direct upload: persist my-photo-ids failed', persistErr);
        }

        onCompleted?.(photoId);
        return { success: true, photoId, warning };
      } catch (err) {
        console.error('Direct upload failed', err);
        triggerHaptic('error');
        const uploadErr = err as UploadError;
        const meta = uploadErr.meta as Record<string, unknown> | undefined;
        const dialog = resolveUploadErrorDialog(uploadErr.code, meta, (v: string) => v);
        setErrorDialog(dialog);
        setError(dialog?.description ?? uploadErr.message ?? 'Upload fehlgeschlagen.');
        setWarning(null);

        if (uploadErr.code === 'demo_read_only') {
          notify(t('upload.demoReadOnly', 'Uploads sind in der Demo deaktiviert.'), 'error');
        }

        if (
          uploadErr.code === 'photo_limit_exceeded'
          || uploadErr.code === 'upload_device_limit'
          || uploadErr.code === 'event_package_missing'
          || uploadErr.code === 'event_not_found'
          || uploadErr.code === 'gallery_expired'
        ) {
          setCanUpload(false);
        }

        if (uploadErr.status === 422 || uploadErr.code === 'validation_error') {
          setWarning('Das Foto war zu groß. Bitte erneut versuchen – wir verkleinern es automatisch.');
        }

        return { success: false, warning, error: dialog?.description ?? uploadErr.message, dialog };
      } finally {
        setUploading(false);
        setProgress((p) => (p === 100 ? p : 0));
      }
    },
    [canUpload, emotionSlug, eventToken, markCompleted, name, preparePhoto, taskId, uploading, warning, onCompleted]
  );

  return {
    upload,
    uploading,
    progress,
    warning,
    error,
    errorDialog,
    reset,
  };
}
