'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */

/* eslint jsx-a11y/no-static-element-interactions: warn */
import { observer } from 'mobx-react-lite';
import { useEffect, useRef, useState } from 'react';
import { useInView } from 'react-intersection-observer';

import { useStores } from '@/app/(root)/AppProviders';
import logWebUserEvent from '@/logging/logWebUserEvent';
import { Clip } from '@/state/clipStore';
import { Project } from '@/state/projectStore';
import {
  DEFAULT_PROJECT_ID,
  SMALL_IMAGE,
  UNTITLED_PROJECT_NAME,
} from '@/utils/constants';
import { getProjectName } from '@/utils/utils';

import Button from '../button/Button';
import ImageWithFallback from '../image/ImageWithFallback';
import SpinnerSVG from '../svg/SpinnerSVG';
import Modal from './Modal';

const AddToProjectModal = observer(
  ({
    isOpen,
    onClose,
    onProjectClick,
    isInCreate,
  }: {
    isOpen: boolean;
    onProjectClick: (clips: Clip[], projectId: string) => void;
    onClose: () => void;
    isInCreate?: boolean;
  }) => {
    const { session, clips: clipsStore, project, menus } = useStores();
    const [createProjectLoading, setCreateProjectLoading] =
      useState<boolean>(false);
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [currentPage, setCurrentPage] = useState(1);
    const [hasMore, setHasMore] = useState(true);
    const [localProjects, setLocalProjects] = useState<
      {
        id: string;
        name: string;
        description: string;
        clip_count: number;
        last_updated_clip: string | null;
      }[]
    >([]);
    const [projectName, setProjectName] = useState('');
    const scrollContainerRef = useRef<HTMLDivElement>(null);

    const { ref: spinnerRef } = useInView({
      threshold: 0,
      onChange: async (inView) => {
        if (inView && hasMore && !isLoading) {
          setCurrentPage((prev) => prev + 1);
        }
      },
    });

    useEffect(() => {
      if (currentPage > 1) {
        fetchProjects(false);
      }
    }, [currentPage]);

    useEffect(() => {
      if (session.userId && isOpen) {
        setLocalProjects([]);
        setHasMore(true);
        fetchProjects(true);
      } else if (!isOpen) {
        setCurrentPage(1);
      }
    }, [session.userId, isOpen]);

    useEffect(() => {
      const handleEscape = (e: KeyboardEvent) => {
        if (e.key === 'Escape' && isOpen) {
          e.preventDefault();
          e.stopPropagation();
          onClose();
        }
      };
      window.addEventListener('keydown', handleEscape, true);
      return () => window.removeEventListener('keydown', handleEscape, true);
    }, [isOpen, onClose]);

    const fetchProjects = async (overwrite: boolean = false) => {
      setIsLoading(true);
      try {
        const { projects, numTotalResults } =
          await project.fetchProjectsList(currentPage);

        if (projects.length === 0) {
          setHasMore(false);
        } else {
          const scrollContainer = scrollContainerRef.current;
          const scrollPosition = scrollContainer?.scrollTop;

          const newProjects = overwrite
            ? projects
            : [
                ...new Map(
                  [...localProjects, ...projects].map((project) => [
                    project.id,
                    project,
                  ])
                ).values(),
              ];

          setLocalProjects(newProjects);
          setHasMore(newProjects.length < numTotalResults);

          if (scrollPosition && scrollContainer) {
            requestAnimationFrame(() => {
              scrollContainer.scrollTop = scrollPosition;
            });
          }
        }
      } catch (error) {
        console.error('Error fetching projects:', error);
      } finally {
        setIsLoading(false);
      }
    };

    if (!isOpen) return null;

    const shouldFilterDefaultProject =
      isInCreate && project.currentProjectId === DEFAULT_PROJECT_ID;

    const shouldFilterCurrentProject = isInCreate;

    const filteredProjects = localProjects.filter(
      (p) =>
        (!shouldFilterDefaultProject || p.id !== DEFAULT_PROJECT_ID) &&
        (!shouldFilterCurrentProject || p.id !== project.currentProjectId)
    );

    return (
      <Modal
        title={'Move to Workspace'}
        onClose={() => {
          onClose();
          logWebUserEvent({
            actionName: 'AddToProjectModalClicked',
            context: { type: 'close' },
          });
        }}
        withHorizontalPadding
        wrapperClasses='max-h-[480px] mb-4'
      >
        <div
          ref={scrollContainerRef}
          className='mb-4 max-h-[400px] overflow-y-auto'
        >
          {!filteredProjects.length && !isLoading && (
            <div className='flex flex-col items-center gap-8 font-sans'>
              <p>
                You have no workspaces to add to. Click below to create a new
                workspace.
              </p>
            </div>
          )}
          {filteredProjects.map((proj) => (
            <div
              key={proj.id}
              className='flex cursor-pointer items-center justify-between rounded-md p-2 hover:bg-secondary/20'
              onClick={() => {
                const selectedClipIds = menus.selectedClipIds;
                if (menus.selectedClipIds && selectedClipIds.length > 0) {
                  onProjectClick(
                    selectedClipIds
                      .map((id: string) => clipsStore.clipById[id])
                      .filter(Boolean),
                    proj.id
                  );
                  menus.setSelected(new Set([]));
                  logWebUserEvent({
                    actionName: 'AddToProjectModalClicked',
                    context: {
                      type: 'add-to-project',
                      projectId: proj.id,
                      originalProjectId: project.currentProjectId,
                      selectedClipIds: selectedClipIds,
                      clipCount: selectedClipIds.length,
                    },
                  });
                }
                onClose();
              }}
            >
              <div className='flex flex-1 items-center overflow-hidden'>
                <div className='h-[40px] w-[53px] shrink-0 overflow-hidden rounded-[8px]'>
                  <ImageWithFallback
                    imageSize={SMALL_IMAGE}
                    src={project.getAuraImageForProject(proj.id)}
                    className='h-full w-full'
                    alt='Workspace cover image'
                    fallbackSrc='https://cdn-o.suno.com/auras/Aura-01.png'
                  />
                </div>
                <div className='ml-4 min-w-0 flex-1 font-sans'>
                  <div className='truncate'>
                    {getProjectName(proj as any as Project)}
                  </div>
                </div>
              </div>
              <div className='text-sm text-foreground-secondary'>
                {proj?.clip_count || 0} clip
                {(proj?.clip_count && proj?.clip_count > 1) ||
                proj?.clip_count === 0
                  ? 's'
                  : ''}
              </div>
            </div>
          ))}
          {hasMore && (
            <div className='flex justify-center p-4'>
              <SpinnerSVG ref={spinnerRef} />
            </div>
          )}
        </div>
        <div className='flex w-full gap-4 whitespace-nowrap'>
          <div className='relative w-full'>
            <input
              className='w-full rounded-md border border-foreground-secondary/20 bg-transparent px-2 py-3 whitespace-nowrap focus-within:outline-white'
              placeholder={UNTITLED_PROJECT_NAME}
              maxLength={100}
              value={projectName?.slice(0, 100) || ''}
              onChange={(e) => setProjectName(e.target.value)}
            />
            <div className='bg-o-50 absolute right-2 bottom-[2px] bg-inherit font-sans text-[12px] text-foreground-secondary opacity-50'>
              {projectName?.length} / 100
            </div>
          </div>
          <Button
            onClick={async () => {
              logWebUserEvent({
                actionName: 'AddToProjectModalClicked',
                context: {
                  type: 'create-project',
                  projectName: projectName,
                  originalProjectId: project.currentProjectId,
                },
              });
              setCreateProjectLoading(true);
              setProjectName('');
              const newProject = await project.createProject(projectName, '');
              setCreateProjectLoading(false);

              const selectedClipIds = menus.selectedClipIds;
              if (
                newProject &&
                menus.selectedClipIds &&
                selectedClipIds.length > 0
              ) {
                onProjectClick(
                  selectedClipIds
                    .map((id: string) => clipsStore.clipById[id])
                    .filter(Boolean),
                  newProject.id
                );
                menus.setSelected(new Set([]));
                logWebUserEvent({
                  actionName: 'AddToProjectModalClicked',
                  context: {
                    type: 'add-to-new-project',
                    projectId: newProject.id,
                    originalProjectId: project.currentProjectId,
                    selectedClipIds: selectedClipIds,
                    clipCount: selectedClipIds.length,
                  },
                });
                onClose();
              }
            }}
          >
            {createProjectLoading ? 'Creating...' : 'Create Workspace'}
          </Button>
        </div>
      </Modal>
    );
  }
);

export default AddToProjectModal;
