'use client';

import { useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { RootState } from '@/store';
import { addPhotos, removePhoto, setNotes, setSaving } from '@/store/slices/installation-slice';
import { InstallationRepository } from '@/repositories/teltoinstall/_index';
import { apiErrorMessage } from '@/utils/teltoinstall/_index';
import { Photo, PhotoType } from '@/models/teltoinstall/_index';

/** A photo selected locally but not yet uploaded to the backend. */
type PendingPhoto = Photo & { file: File };

export function usePhotosStep() {
  const { t } = useTranslation();
  const dispatch = useDispatch();
  const { photos: uploadedPhotos, notes, installationId } = useSelector(
    (state: RootState) => state.installation
  );
  const [pending, setPending] = useState<PendingPhoto[]>([]);
  const [uploading, setUploading] = useState(false);
  const [uploadError, setUploadError] = useState<string | null>(null);

  // Revoke any outstanding preview object URLs when leaving the step.
  const pendingRef = useRef<PendingPhoto[]>(pending);
  pendingRef.current = pending;
  useEffect(() => {
    return () => {
      pendingRef.current.forEach((p) => p.url && URL.revokeObjectURL(p.url));
    };
  }, []);

  // Already-uploaded photos (from backend) + locally selected previews.
  const photos: Photo[] = [...uploadedPhotos, ...pending];

  /** Add files locally for preview only — nothing is sent to the backend yet. */
  function addFiles(files: File[], type: PhotoType) {
    const newPending: PendingPhoto[] = files.map((file) => ({
      type,
      file,
      url: URL.createObjectURL(file),
      filename: file.name,
    }));
    setPending((prev) => [...prev, ...newPending]);
  }

  /** Delete by index into the merged `photos` list. */
  async function deletePhoto(index: number) {
    if (index < uploadedPhotos.length) {
      const photo = uploadedPhotos[index];
      if (installationId && photo?.id) {
        try {
          await InstallationRepository.deletePhoto(installationId, photo.id);
        } catch {
          // still remove from local state even if API call fails
        }
      }
      dispatch(removePhoto(index));
    } else {
      const pendingIndex = index - uploadedPhotos.length;
      const photo = pending[pendingIndex];
      if (photo?.url) URL.revokeObjectURL(photo.url);
      setPending((prev) => prev.filter((_, i) => i !== pendingIndex));
    }
  }

  /**
   * Persist this step on "Suivant": upload pending photos and save notes.
   * Returns false (without clearing successfully uploaded items) if the
   * backend fails, so the wizard can keep the user on this step.
   */
  async function savePhotosStep(): Promise<boolean> {
    if (!installationId) return false;
    setUploading(true);
    dispatch(setSaving(true));
    setUploadError(null);

    const succeeded = new Set<PendingPhoto>();
    try {
      const groups = new Map<PhotoType, PendingPhoto[]>();
      pending.forEach((p) => {
        const arr = groups.get(p.type) ?? [];
        arr.push(p);
        groups.set(p.type, arr);
      });

      for (const [type, items] of groups) {
        const uploaded = await InstallationRepository.uploadPhotos(
          installationId,
          items.map((i) => i.file),
          type
        );
        dispatch(addPhotos(uploaded));
        items.forEach((i) => {
          if (i.url) URL.revokeObjectURL(i.url);
          succeeded.add(i);
        });
      }

      await InstallationRepository.update(installationId, { notes });

      setPending([]);
      return true;
    } catch (err) {
      // Keep only the items that were not yet uploaded, to avoid duplicates on retry.
      setPending((prev) => prev.filter((p) => !succeeded.has(p)));
      setUploadError(apiErrorMessage(err, t('errors.generic')));
      return false;
    } finally {
      setUploading(false);
      dispatch(setSaving(false));
    }
  }

  function updateNotes(value: string) {
    dispatch(setNotes(value));
  }

  const photosByType = (type: PhotoType) => photos.filter((p) => p.type === type);

  return {
    photos,
    notes,
    uploading,
    uploadError,
    addFiles,
    deletePhoto,
    savePhotosStep,
    updateNotes,
    photosByType,
  };
}
