'use client';

import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
import { QueryClient } from '@tanstack/react-query';
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import { useEffect, useRef } from 'react';
import { useIsClient, useMediaQuery } from 'usehooks-ts';

import { useStores } from '@/app/(root)/AppProviders';
import useClip from '@/hooks/useClip';
import { useApiClient } from '@/lib/apiClient';
import { PlanFeature } from '@/state/sessionStore';
import { isFeatureEnabledForPlan } from '@/utils/session';
import { staticAssetUrl } from '@/utils/staticAssetUrl';

import Button from '../button/Button';
import {
  Axis,
  Divider,
  HorizontalPanelGroup,
  Panel,
  PanelGroup,
  VerticalPanelGroup,
} from '../panelSystem/PanelSystem';
import EditHeader from './EditHeader';
import EditList from './EditList';
import EditModeContext, {
  EditMode,
  useEditModeContext,
} from './EditModeContext';
import { EditPlaybackContextProvider } from './EditPlaybackContext';
import EditRootClipContext from './EditRootClipContext';
import EditSpeed from './EditSpeed';
import EditStyles from './EditStyles';
import EditStylesContext, { useEditStylesContext } from './EditStylesContext';
import { EditTimelineProvider } from './EditTimelineContext';
import EditWelcome from './EditWelcome';
import GenerateContext, { useGenerateContext } from './GenerateContext';
import MultiTrackTimeline from './MultiTrackTimeline';
import PreviewClipContext, {
  usePreviewClipContext,
} from './PreviewClipContext';
import SelectionContext, {
  DEFAULT_SELECTION_LENGTH,
  useSelectionContext,
} from './SelectionContext';
import SingleTrackTimeline from './SingleTrackTimeline';
import StemsContext, { useStemsContext } from './StemsContext';
import { precomputeWaveformAggregates } from './canvasRenderer/renderWaveform';
import { ModuleDivider } from './components';
import { AlignedLyricsProvider } from './lyrics/AlignedLyricsContext';
import AlignedLyricsEditor from './lyrics/AlignedLyricsEditor';
import EditTimingContext, {
  useEditTimingContext,
} from './queryHooks/EditTimingContext';

const oneFRPanelSize = { unit: 'fr', count: 1 } as const;
const fourFiftyPxPanelSize = { unit: 'px', count: 450 } as const;

const Wrapper = styled.div`
  width: 100vw;
  height: 100vh;
  position: relative;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
`;

const BlurryBackground = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  transition: opacity 0.4s ease;
  pointer-events: none;
  background-size: cover;
  background-image: url(${staticAssetUrl('edit-bg-blur.webp')});
`;

const ModuleSectionWrapper = styled.div<{ fadeOut: boolean }>`
  height: 100%;
  width: 100%;
  padding: 0 10px;
  opacity: ${({ fadeOut }) => (fadeOut ? 0 : 1)};
  transition: opacity 0.4s;
  position: relative;
`;

const LoadingOverlay = styled.div<{ active: boolean }>`
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: ${({ active }) => (active ? 'auto' : 'none')};
  ${({ active }) => `
    opacity: ${active ? 1 : 0};
  `}
  background-color: rgba(0, 0, 0, 0.6);
  background-image: radial-gradient(
    circle,
    rgba(0, 0, 0, 0.9),
    rgba(0, 0, 0, 0)
  );
  backdrop-filter: blur(5px) saturate(0.5);
  > * {
    opacity: ${({ active }) => (active ? 1 : 0)};
    pointer-events: ${({ active }) => (active ? 'auto' : 'none')};
    transition: opacity 0.8s;
  }
  transition: opacity 0.8s;
`;

const VideoWrapper = styled.div`
  width: 600px;
  height: 200px;
  position: relative;
`;

const OverlayText = styled.div`
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: -20px;
  font-size: 22px;
  color: rgba(255, 255, 255, 0.8);
`;

const slowFadeIn = keyframes`
  0% {
    opacity: 0;
  }
  95% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
`;

const OverlaySubMessage = styled.div<{ enabled: boolean }>`
  cursor: pointer;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.5);
  opacity: 0;
  margin-top: -20px;
  z-index: 6;
  text-align: center;
  ${({ enabled }) => (!enabled ? 'pointer-events: none; left: -10000px;' : '')}
  animation: ${({ enabled }) => (enabled ? slowFadeIn : '')} 30s forwards;
  span {
    text-decoration: underline;
    &:hover {
      color: white;
    }
  }
`;

const MainGroupScrollWrapper = styled.div<{ scrollable: boolean }>`
  ${({ scrollable }) =>
    scrollable
      ? `
        overflow-y: auto;
        height: 100%;
      `
      : 'height: 100%;'}
`;

const messagesByEditType: Partial<Record<EditMode, string>> = {
  crop: 'Cropping Clip...',
  extend: 'Extending Clip...',
  fadeOut: 'Fading Out Clip...',
  replace: 'Applying Replacement...',
  remove: 'Removing Section...',
  speed: 'Changing Speed...',
  stems: 'Exporting Song...',
};

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
    },
  },
});

const hasLocalStorage = typeof localStorage !== 'undefined';

const persister = createSyncStoragePersister({
  storage: hasLocalStorage ? localStorage : undefined,
});

const topPanelSize = { unit: 'px', count: 60 } as const;
const bottomPanelSize = {
  unit: 'px',
  count: 325,
} as const;

export default observer(function Edit2025() {
  const pathname = usePathname();
  const clipId = pathname.split('/').pop() as string;
  const { clip, error } = useClip(clipId);
  const { playbar, session, edit } = useStores();
  const apiClient = useApiClient();
  const enableEditList =
    useIsClient() && isFeatureEnabledForPlan(session, PlanFeature.EditMode);

  // Precompute waveform aggregates when clip is loaded
  const precomputedClipRef = useRef<string | null>(null);
  useEffect(() => {
    if (clip && clipId && precomputedClipRef.current !== clipId) {
      precomputedClipRef.current = clipId;
      precomputeWaveformAggregates(apiClient, clipId).catch((error) => {
        console.error(
          `Failed to precompute waveform aggregates for clip ${clipId}:`,
          error
        );
      });
    }
  }, [clip, clipId, apiClient]);

  const generateContext = useGenerateContext(clipId);
  const editModeContext = useEditModeContext();
  const previewClipContext = usePreviewClipContext(clipId, editModeContext);
  const timing = useEditTimingContext(clipId);
  const selectionContext = useSelectionContext(
    editModeContext.editMode,
    previewClipContext.songEndSeconds,
    timing
  );
  const editStylesContext = useEditStylesContext();
  const stemsContext = useStemsContext(clipId);

  useEffect(() => {
    playbar.unsetClip();
  }, [playbar.clip, playbar.unsetClip]);

  const lastClipIdRef = useRef(clipId);
  useEffect(() => {
    if (
      clipId !== lastClipIdRef.current &&
      previewClipContext.songEndSeconds > 0
    ) {
      selectionContext.setSelection([
        0,
        Math.min(previewClipContext.songEndSeconds, DEFAULT_SELECTION_LENGTH),
      ]);
      lastClipIdRef.current = clipId;
    }
  }, [clipId, previewClipContext.songEndSeconds]);

  useEffect(() => {
    edit.setEditTool(
      {
        replace: 'infill',
        extend: 'extend',
        crop: 'crop',
        remove: 'crop',
        fadeOut: 'fadeOut',
        none: 'none',
        speed: 'speed_change',
        fixLyrics: 'edit_details',
        stems: 'stems',
      }[editModeContext.editMode]
    );
    edit.setEditingClipId(clipId);
  }, [editModeContext.editMode, clipId]);

  useEffect(() => {
    document.body.style.overscrollBehaviorX = 'contain';
    document.body.parentElement!.style.overscrollBehaviorX = 'contain';

    return () => {
      document.body.style.overscrollBehaviorX = '';
      document.body.parentElement!.style.overscrollBehaviorX = '';
    };
  });

  const rootClipLoading = clip?.status !== 'complete';

  const loadingOverlayActive = previewClipContext.applying || rootClipLoading;

  const narrowScreen = useMediaQuery('(max-width: 1200px)');

  if (error) {
    return (
      <div className='flex h-full w-full flex-col items-center justify-center'>
        <p className='text-2xl'>Error loading clip</p>
        <p className='mb-4 text-sm'>{error}</p>
        <Button href='/create'>Back to Create Page</Button>
      </div>
    );
  }

  return (
    <EditRootClipContext.Provider value={clipId}>
      <PersistQueryClientProvider
        client={queryClient}
        persistOptions={{ persister }}
      >
        <StemsContext.Provider value={stemsContext}>
          <GenerateContext.Provider value={generateContext}>
            <EditStylesContext.Provider value={editStylesContext}>
              <PreviewClipContext.Provider value={previewClipContext}>
                <SelectionContext.Provider value={selectionContext}>
                  <AlignedLyricsProvider clipId={clipId}>
                    <EditModeContext.Provider value={editModeContext}>
                      <EditTimingContext.Provider value={timing}>
                        <EditPlaybackContextProvider>
                          <EditTimelineProvider>
                            <Wrapper>
                              <LoadingOverlay active={loadingOverlayActive}>
                                <VideoWrapper>
                                  <video
                                    key='editor-loading-video'
                                    autoPlay
                                    loop
                                    muted
                                    playsInline
                                    className='min-h-full min-w-full object-cover'
                                  >
                                    <source
                                      src={staticAssetUrl(
                                        'editor-loading-bg.webm'
                                      )}
                                      type='video/mp4'
                                    />
                                  </video>
                                  <OverlayText>
                                    {messagesByEditType[
                                      editModeContext.lastAppliedEditType ||
                                        'none'
                                    ] || 'Preparing Editor...'}
                                  </OverlayText>
                                </VideoWrapper>
                                <OverlaySubMessage
                                  enabled={loadingOverlayActive}
                                  onClick={() => window.location.reload()}
                                >
                                  If this message persists, click here to{' '}
                                  <span>reload the page.</span>
                                </OverlaySubMessage>
                              </LoadingOverlay>
                              <BlurryBackground
                                style={
                                  !loadingOverlayActive
                                    ? {
                                        opacity: 1,
                                      }
                                    : { opacity: 0 }
                                }
                              />
                              <VerticalPanelGroup>
                                <Panel size={topPanelSize}>
                                  <EditHeader clipId={clipId} />
                                </Panel>
                                <Divider influence='neither'>
                                  <ModuleDivider />
                                </Divider>
                                {editModeContext.editMode === 'stems' ? (
                                  <Panel size={oneFRPanelSize}>
                                    <MultiTrackTimeline
                                      clipId={clipId}
                                      fadeOut={loadingOverlayActive}
                                    />
                                  </Panel>
                                ) : (
                                  <>
                                    <Panel size={oneFRPanelSize}>
                                      <ModuleSectionWrapper
                                        fadeOut={loadingOverlayActive}
                                      >
                                        {editModeContext.editMode ===
                                        'fixLyrics' ? (
                                          <HorizontalPanelGroup>
                                            <Panel size={oneFRPanelSize}>
                                              <div className='flex h-full flex-col items-center justify-center gap-4'>
                                                <p className='w-full max-w-80'>
                                                  Use this tool to correct
                                                  issues where the written
                                                  lyrics do not match the lyrics
                                                  you hear in your song.
                                                </p>
                                              </div>
                                            </Panel>
                                            <Divider>
                                              <ModuleDivider />
                                            </Divider>
                                            <Panel size={oneFRPanelSize}>
                                              <AlignedLyricsEditor />
                                            </Panel>
                                          </HorizontalPanelGroup>
                                        ) : editModeContext.editMode ===
                                          'speed' ? (
                                          <EditSpeed clipId={clipId} />
                                        ) : ['extend', 'replace'].includes(
                                            editModeContext.editMode
                                          ) ? (
                                          <MainGroupScrollWrapper
                                            scrollable={narrowScreen}
                                          >
                                            <PanelGroup
                                              axis={
                                                narrowScreen
                                                  ? Axis.Vertical
                                                  : Axis.Horizontal
                                              }
                                            >
                                              <Panel
                                                size={oneFRPanelSize}
                                                minSizePx={200}
                                              >
                                                <AlignedLyricsEditor />
                                              </Panel>
                                              <Divider>
                                                <ModuleDivider />
                                              </Divider>
                                              <Panel
                                                size={oneFRPanelSize}
                                                minSizePx={200}
                                              >
                                                <EditStyles clipId={clipId} />
                                              </Panel>
                                              {enableEditList ? (
                                                <>
                                                  <Divider>
                                                    <ModuleDivider />
                                                  </Divider>
                                                  <Panel
                                                    size={
                                                      narrowScreen
                                                        ? oneFRPanelSize
                                                        : fourFiftyPxPanelSize
                                                    }
                                                    minSizePx={200}
                                                  >
                                                    <EditList clipId={clipId} />
                                                  </Panel>
                                                </>
                                              ) : null}
                                            </PanelGroup>
                                          </MainGroupScrollWrapper>
                                        ) : editModeContext.editMode ===
                                          'none' ? (
                                          <EditWelcome
                                            clipId={clipId}
                                            visible={!loadingOverlayActive}
                                          />
                                        ) : null}
                                      </ModuleSectionWrapper>
                                    </Panel>
                                    <Divider>
                                      <ModuleDivider />
                                    </Divider>
                                    <Panel size={bottomPanelSize}>
                                      <SingleTrackTimeline
                                        clipId={clipId}
                                        fadeOut={loadingOverlayActive}
                                      />
                                    </Panel>
                                  </>
                                )}
                              </VerticalPanelGroup>
                            </Wrapper>
                          </EditTimelineProvider>
                        </EditPlaybackContextProvider>
                      </EditTimingContext.Provider>
                    </EditModeContext.Provider>
                  </AlignedLyricsProvider>
                </SelectionContext.Provider>
              </PreviewClipContext.Provider>
            </EditStylesContext.Provider>
          </GenerateContext.Provider>
        </StemsContext.Provider>
      </PersistQueryClientProvider>
    </EditRootClipContext.Provider>
  );
});
