'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';

import { SongifyProject, SongifyProjectStatus } from '@/types/songify';

import { CreateProjectOptions, useSongifyActions } from './useSongifyActions';
import { useSongifyProjects } from './useSongifyProjects';
import { useSongifyStatusPolling } from './useSongifyStatusPolling';

export interface UseSongifyOptions {
  enablePolling?: boolean;
}

export function useSongify(options: UseSongifyOptions = {}) {
  const { enablePolling = true } = options;

  const [selectedProject, setSelectedProject] = useState<SongifyProject | null>(
    null
  );

  // Core hooks
  const projectsHook = useSongifyProjects();
  const actionsHook = useSongifyActions();

  // Status polling for selected project
  const statusPolling = useSongifyStatusPolling({
    songifyId: selectedProject?.requestId || null,
    initialStatus: selectedProject?.status || SongifyProjectStatus.PENDING,
    onStatusUpdate: projectsHook.handleStatusUpdate,
    isProjectStale: projectsHook.isProjectStale,
    enabled:
      enablePolling &&
      !!selectedProject?.requestId &&
      !selectedProject?.requestId.startsWith('temp_'),
  });

  // Update selected project when projects list changes (e.g., from status updates)
  useEffect(() => {
    if (selectedProject) {
      const updatedProject = projectsHook.projects.find(
        (p: SongifyProject) => p.requestId === selectedProject.requestId
      );
      if (updatedProject && updatedProject !== selectedProject) {
        console.log(
          `[Songify] Updating selected project status from ${selectedProject.status} to ${updatedProject.status}`
        );
        setSelectedProject(updatedProject);
      }
    }
  }, [projectsHook.projects, selectedProject]);

  // Create a new project
  const createProject = useCallback(
    async (options: CreateProjectOptions) => {
      try {
        const result = await actionsHook.createProject.mutateAsync(options);

        // Select the new project
        setSelectedProject(result.project);

        return result;
      } catch (error) {
        console.error('Failed to create project:', error);
        throw error;
      }
    },
    [actionsHook.createProject]
  );

  // Regenerate an existing project
  const regenerateProject = useCallback(
    async (originalProject: SongifyProject) => {
      const newName = projectsHook.getIncrementedProjectName(
        originalProject.name
      );

      try {
        const result = await actionsHook.regenerateProject.mutateAsync({
          originalProject,
          newName,
        });

        // Select the new project
        setSelectedProject(result.project);

        return result;
      } catch (error) {
        console.error('Failed to regenerate project:', error);
        throw error;
      }
    },
    [actionsHook.regenerateProject, projectsHook.getIncrementedProjectName]
  );

  // Update project metadata
  const updateProject = useCallback(
    async (
      requestId: string,
      updates: Partial<Pick<SongifyProject, 'name'>>
    ) => {
      try {
        await actionsHook.updateProject.mutateAsync({ requestId, updates });

        // Update selected project if it matches
        if (selectedProject?.requestId === requestId) {
          setSelectedProject((prev) => (prev ? { ...prev, ...updates } : null));
        }
      } catch (error) {
        console.error('Failed to update project:', error);
        throw error;
      }
    },
    [actionsHook.updateProject, selectedProject]
  );

  // Delete a project
  const deleteProject = useCallback(
    async (requestId: string) => {
      try {
        await actionsHook.deleteProject.mutateAsync(requestId);

        // Clear selection if deleted project was selected
        if (selectedProject?.requestId === requestId) {
          setSelectedProject(null);
        }
      } catch (error) {
        console.error('Failed to delete project:', error);
        throw error;
      }
    },
    [actionsHook.deleteProject, selectedProject]
  );

  // Delete all projects
  const deleteAllProjects = useCallback(async () => {
    await actionsHook.deleteAllProjects.mutateAsync();
    setSelectedProject(null);
  }, [actionsHook.deleteAllProjects]);

  // Select a project (for viewing/editing)
  const selectProject = useCallback((project: SongifyProject | null) => {
    setSelectedProject(project);
  }, []);

  // Get project by ID
  const getProject = useCallback(
    (requestId: string) => {
      return (
        projectsHook.projects.find(
          (p: SongifyProject) => p.requestId === requestId
        ) || null
      );
    },
    [projectsHook.projects]
  );

  // Check if any projects are currently processing
  const hasActiveProjects = useMemo(() => {
    return projectsHook.projects.some(
      (project: SongifyProject) =>
        project.status === SongifyProjectStatus.PENDING ||
        project.status === SongifyProjectStatus.PROCESSING_UPLOAD ||
        project.status === SongifyProjectStatus.GENERATING_REMIXES ||
        project.status === SongifyProjectStatus.GENERATING_VIDEOS
    );
  }, [projectsHook.projects]);

  // Get projects by status
  const getProjectsByStatus = useCallback(
    (status: SongifyProjectStatus) => {
      return projectsHook.projects.filter(
        (project: SongifyProject) => project.status === status
      );
    },
    [projectsHook.projects]
  );

  return {
    // Data
    projects: projectsHook.projects,
    selectedProject,

    // Loading states
    isLoading: projectsHook.isLoading,
    isCreating: actionsHook.isCreating,
    isRegenerating: actionsHook.isRegenerating,
    isUpdating: actionsHook.isUpdating,
    isDeleting: actionsHook.isDeleting,
    isPolling: statusPolling.isPolling,

    // Status info
    hasActiveProjects,
    statusData: statusPolling.statusData,

    // Actions
    createProject,
    regenerateProject,
    updateProject,
    deleteProject,
    deleteAllProjects,
    selectProject,

    // Utilities
    getProject,
    getProjectsByStatus,
    getIncrementedProjectName: projectsHook.getIncrementedProjectName,

    // File upload
    getPresignedUrl: actionsHook.getPresignedUrl.mutateAsync,
    isGettingUploadUrl: actionsHook.isGettingUploadUrl,

    // Error states
    error: projectsHook.error,
    statusError: statusPolling.error,
  };
}
