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

import { useContextSelector } from '@/hooks/useContextSelector';
import ContextualStudioEventType, {
  StudioTrackingContext,
} from '@/logging/eventTypes/StudioEventType';
import logWebUserEvent, { TransactionLogger } from '@/logging/logWebUserEvent';

import StudioContext from './StudioContext';
import { StudioProjectManagementContext } from './StudioProjectManagementContext';
import {
  getSelectionEndBeats,
  getSelectionStartBeats,
  getSongEndBeats,
  getSongStartBeats,
} from './selectors';
import { StudioLayoutManagerContext } from './useStudioLayoutManager';

export const useLogStudioWebUserEvent = (): ((
  eventWithoutStudioContext: ContextualStudioEventType & {
    context: Omit<
      ContextualStudioEventType['context'],
      keyof StudioTrackingContext
    >;
  },
  transactionLogger?: TransactionLogger
) => void) => {
  const [lastProjectChangeTimestamp, setLastProjectChangeTimestamp] = useState(
    Date.now()
  );

  const studioProjectId = useContextSelector(
    StudioContext,
    (ctx) => ctx.studioProjectId
  );
  useEffect(() => {
    setLastProjectChangeTimestamp(Date.now());
  }, [studioProjectId]);

  const numTracks = useContextSelector(
    StudioContext,
    (ctx) => ctx.state.tracks.length
  );
  const numMutedTracks = useContextSelector(
    StudioContext,
    (ctx) => ctx.state.tracks.filter((track) => track.mute).length
  );
  const numSoloedTracks = useContextSelector(
    StudioContext,
    (ctx) => ctx.state.tracks.filter((track) => track.solo).length
  );
  const numTakeLanes = useContextSelector(StudioContext, (ctx) =>
    ctx.state.tracks.reduce((acc, track) => acc + track.takeLanes.length, 0)
  );
  const lastSavedVersionId = useContextSelector(
    StudioProjectManagementContext,
    (ctx) => ctx.latestVersionId
  );
  const numClipsOnTracks = useContextSelector(StudioContext, (ctx) =>
    ctx.state.tracks.reduce((acc, track) => acc + track.clips.length, 0)
  );
  const numClipsOnTakeLanes = useContextSelector(StudioContext, (ctx) =>
    ctx.state.tracks.reduce(
      (acc, track) =>
        acc +
        track.takeLanes.reduce(
          (acc, takeLane) => acc + takeLane.clips.length,
          0
        ),
      0
    )
  );
  const numMutedClips = useContextSelector(StudioContext, (ctx) =>
    ctx.state.tracks.reduce(
      (acc, track) => acc + track.clips.filter((clip) => clip.mute).length,
      0
    )
  );
  const projectLoopEnabled = useContextSelector(
    StudioContext,
    (ctx) => ctx.state.loop.enabled
  );
  const selectionStartBeats = useContextSelector(StudioContext, (ctx) =>
    getSelectionStartBeats(ctx.state)
  );
  const selectionEndBeats = useContextSelector(StudioContext, (ctx) =>
    getSelectionEndBeats(ctx.state)
  );
  const songStartBeats = useContextSelector(StudioContext, (ctx) =>
    getSongStartBeats(ctx.state)
  );
  const songEndBeats = useContextSelector(StudioContext, (ctx) =>
    getSongEndBeats(ctx.state)
  );

  const showingNavSidebar = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.showNav
  );
  const createPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.createPanelExpanded
  );
  const libraryPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.libraryPanelExpanded
  );
  const sessionPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.sessionPanelExpanded
  );
  const focusedObjectPanelExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.focusedObjectPanelExpanded
  );
  const contextualBarExpanded = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.contextualBarExpanded
  );
  const layoutMode = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.layoutMode
  );
  const createPanelWrapperRef = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.createPanelWrapperRef
  );
  const libraryPanelWrapperRef = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.libraryPanelWrapperRef
  );
  const sessionPanelWrapperRef = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.sessionPanelWrapperRef
  );
  const focusedObjectPanelWrapperRef = useContextSelector(
    StudioLayoutManagerContext,
    (ctx) => ctx!.focusedObjectPanelWrapperRef
  );

  const logStudioWebUserEvent = useCallback(
    (
      eventWithoutStudioContext: ContextualStudioEventType,
      transactionLogger?: TransactionLogger
    ) => {
      const createPanelWidthPx =
        createPanelWrapperRef.current?.clientWidth ?? null;
      const createPanelHeightPx =
        createPanelWrapperRef.current?.clientHeight ?? null;
      const libraryPanelWidthPx =
        libraryPanelWrapperRef.current?.clientWidth ?? null;
      const libraryPanelHeightPx =
        libraryPanelWrapperRef.current?.clientHeight ?? null;
      const sessionPanelWidthPx =
        sessionPanelWrapperRef.current?.clientWidth ?? null;
      const sessionPanelHeightPx =
        sessionPanelWrapperRef.current?.clientHeight ?? null;
      const focusedObjectPanelWidthPx =
        focusedObjectPanelWrapperRef.current?.clientWidth ?? null;
      const focusedObjectPanelHeightPx =
        focusedObjectPanelWrapperRef.current?.clientHeight ?? null;

      const studioContext: StudioTrackingContext = {
        numTracks,
        numMutedTracks,
        numSoloedTracks,
        numTakeLanes,
        numClipsOnTracks,
        numClipsOnTakeLanes,
        numMutedClips,

        selectionStartBeats,
        selectionEndBeats,
        songStartBeats,
        songEndBeats,

        projectLoopEnabled,
        lastSavedVersionId,

        showingNavSidebar,
        createPanelExpanded,
        createPanelWidthPx,
        createPanelHeightPx,
        libraryPanelWidthPx,
        libraryPanelHeightPx,
        sessionPanelWidthPx,
        sessionPanelHeightPx,
        focusedObjectPanelWidthPx,
        focusedObjectPanelHeightPx,
        libraryPanelExpanded,
        sessionPanelExpanded,
        focusedObjectPanelExpanded,
        contextualBarExpanded,
        layoutMode,

        studioProjectId,
        timeSinceLastProjectOpenSeconds:
          (Date.now() - lastProjectChangeTimestamp) / 1000,
      };

      const finalEvent = {
        ...eventWithoutStudioContext,
        context: {
          ...eventWithoutStudioContext.context,
          ...studioContext,
        } as any,
      };

      if (transactionLogger) {
        transactionLogger.logWebUserEvent(finalEvent);
      } else {
        logWebUserEvent(finalEvent);
      }
    },
    [
      numTracks,
      numMutedTracks,
      numSoloedTracks,
      numTakeLanes,
      numClipsOnTracks,
      numClipsOnTakeLanes,
      numMutedClips,
      projectLoopEnabled,
      lastSavedVersionId,
      showingNavSidebar,
      createPanelExpanded,
      libraryPanelExpanded,
      sessionPanelExpanded,
      focusedObjectPanelExpanded,
      layoutMode,
      contextualBarExpanded,
      studioProjectId,
      lastProjectChangeTimestamp,
    ]
  );

  return logStudioWebUserEvent;
};
