'use client';

import { useState, useEffect, ReactNode, useCallback, useRef } from 'react';
import { AppStateContext } from './AppState';
import { AnimationConfig } from '@/components/AnimateItems';
import usePathnames from '@/utility/usePathnames';
import { getAuthAction } from '@/auth/actions';
import useSWR from 'swr';
import {
  HIGH_DENSITY_GRID,
  IS_DEVELOPMENT,
  MATTE_PHOTOS,
  SHOW_ZOOM_CONTROLS,
} from '@/app/config';
import { ShareModalProps } from '@/share';
import { storeTimezoneCookie } from '@/utility/timezone';
import { InsightIndicatorStatus } from '@/admin/insights';
import { getAdminDataAction } from '@/admin/actions';
import {
  storeAuthEmailCookie,
  clearAuthEmailCookie,
  hasAuthEmailCookie,
} from '@/auth/client';
import { useRouter } from 'next/navigation';
import { PATH_SIGN_IN } from '@/app/paths';
import { INITIAL_UPLOAD_STATE, UploadState } from '@/admin/upload';

export default function AppStateProvider({
  children,
}: {
  children: ReactNode
}) {
  const router = useRouter();

  const { previousPathname } = usePathnames();

  // CORE
  const [hasLoaded, setHasLoaded] =
    useState(false);
  const [swrTimestamp, setSwrTimestamp] =
    useState(Date.now());
  const [nextPhotoAnimation, setNextPhotoAnimation] =
    useState<AnimationConfig>();
  const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] =
    useState(true);
  // UPLOAD
  const uploadInputRef = useRef<HTMLInputElement>(null);
  const [uploadState, _setUploadState] =
    useState(INITIAL_UPLOAD_STATE);
  // MODAL
  const [isCommandKOpen, setIsCommandKOpen] =
    useState(false);
  const [shareModalProps, setShareModalProps] =
    useState<ShareModalProps>();
  // AUTH
  const [userEmail, setUserEmail] =
    useState<string>();
  const [isUserSignedInEager, setIsUserSignedInEager] =
    useState(false);
  // ADMIN
  const [adminUpdateTimes, setAdminUpdateTimes] =
    useState<Date[]>([]);
  const [photosCount, setPhotosCount] =
    useState<number>();
  const [photosCountHidden, setPhotosCountHidden] =
    useState<number>();
  const [uploadsCount, setUploadsCount] =
    useState<number>();
  const [tagsCount, setTagsCount] =
    useState<number>();
  const [selectedPhotoIds, setSelectedPhotoIds] =
    useState<string[] | undefined>();
  const [isPerformingSelectEdit, setIsPerformingSelectEdit] =
    useState(false);
  const [insightIndicatorStatus, setInsightIndicatorStatus] =
    useState<InsightIndicatorStatus>();
  // DEBUG
  const [isGridHighDensity, setIsGridHighDensity] =
    useState(HIGH_DENSITY_GRID);
  const [areZoomControlsShown, setAreZoomControlsShown] =
    useState(SHOW_ZOOM_CONTROLS);
  const [arePhotosMatted, setArePhotosMatted] =
    useState(MATTE_PHOTOS);
  const [shouldDebugImageFallbacks, setShouldDebugImageFallbacks] =
    useState(false);
  const [shouldShowBaselineGrid, setShouldShowBaselineGrid] =
    useState(false);
  const [shouldDebugInsights, setShouldDebugInsights] =
    useState(IS_DEVELOPMENT);
  const [shouldDebugRecipeOverlays, setShouldDebugRecipeOverlays] =
    useState(false);

  const photosCountTotal = (
    photosCount !== undefined &&
    photosCountHidden !== undefined
  )
    ? photosCount + photosCountHidden
    : undefined;

  const startUpload = useCallback((onStart?: () => void) => {
    if (uploadInputRef.current) {
      uploadInputRef.current.value = '';
      uploadInputRef.current.click();
      uploadInputRef.current.oninput = onStart ?? null;
      uploadInputRef.current.oncancel = onStart ?? null;
    }
  }, []);
  const setUploadState = useCallback((uploadState: Partial<UploadState>) => {
    _setUploadState(prev => ({ ...prev, ...uploadState }));
  }, []);
  const resetUploadState = useCallback(() => {
    _setUploadState(INITIAL_UPLOAD_STATE);
  }, []);

  const invalidateSwr = useCallback(() => setSwrTimestamp(Date.now()), []);

  const { data: auth, error: authError } = useSWR('getAuth', getAuthAction);
  useEffect(() => {
    setIsUserSignedInEager(hasAuthEmailCookie());
    if (!authError) {
      setUserEmail(auth?.user?.email ?? undefined);
    }
  }, [auth, authError]);
  const isUserSignedIn = Boolean(userEmail);

  const { data: adminData, mutate: refreshAdminData } = useSWR(
    isUserSignedIn ? 'getAdminData' : null,
    getAdminDataAction, {
      refreshInterval: 1000 * 60,
    },
  );

  useEffect(() => {
    if (userEmail) {
      storeAuthEmailCookie(userEmail);
      if (adminData) {
        setPhotosCount(adminData.countPhotos);
        setPhotosCountHidden(adminData.countHiddenPhotos);
        setUploadsCount(adminData.countUploads);
        setTagsCount(adminData.countTags);
        setInsightIndicatorStatus(adminData.shouldShowInsightsIndicator);
      }
    } else {
      setPhotosCountHidden(0);
    }
  }, [adminData, userEmail]);

  const registerAdminUpdate = useCallback(() =>
    setAdminUpdateTimes(updates => [...updates, new Date()])
  , []);

  useEffect(() => {
    setHasLoaded?.(true);
    storeTimezoneCookie();
  }, []);

  const clearAuthStateAndRedirect = useCallback((shouldRedirect = true) => {
    setUserEmail(undefined);
    setIsUserSignedInEager(false);
    clearAuthEmailCookie();
    if (shouldRedirect) { router.push(PATH_SIGN_IN); }
  }, [router]);

  return (
    <AppStateContext.Provider
      value={{
        // CORE
        previousPathname,
        hasLoaded,
        setHasLoaded,
        swrTimestamp,
        invalidateSwr,
        nextPhotoAnimation,
        setNextPhotoAnimation,
        clearNextPhotoAnimation: () => setNextPhotoAnimation?.(undefined),
        shouldRespondToKeyboardCommands,
        setShouldRespondToKeyboardCommands,
        // UPLOAD
        uploadInputRef,
        startUpload,
        uploadState,
        setUploadState,
        resetUploadState,
        // MODAL
        isCommandKOpen,
        setIsCommandKOpen,
        shareModalProps,
        setShareModalProps,
        // AUTH
        userEmail,
        setUserEmail,
        isUserSignedIn,
        isUserSignedInEager,
        clearAuthStateAndRedirect,
        // ADMIN
        adminUpdateTimes,
        registerAdminUpdate,
        refreshAdminData,
        photosCount,
        photosCountHidden,
        photosCountTotal,
        uploadsCount,
        tagsCount,
        selectedPhotoIds,
        setSelectedPhotoIds,
        isPerformingSelectEdit,
        setIsPerformingSelectEdit,
        insightIndicatorStatus,
        setInsightIndicatorStatus,
        // DEBUG
        isGridHighDensity,
        setIsGridHighDensity,
        areZoomControlsShown,
        setAreZoomControlsShown,
        arePhotosMatted,
        setArePhotosMatted,
        shouldDebugImageFallbacks,
        setShouldDebugImageFallbacks,
        shouldShowBaselineGrid,
        setShouldShowBaselineGrid,
        shouldDebugInsights,
        setShouldDebugInsights,
        shouldDebugRecipeOverlays,
        setShouldDebugRecipeOverlays,
      }}
    >
      {children}
    </AppStateContext.Provider>
  );
};
