'use client';

import React, { useCallback, useEffect, useRef, useState } from 'react';
import { SessionProvider, getSession, getCsrfToken } from 'next-auth/react';
import axiosInstance from '@/utills/axiosInstance';
import Layout from '../components/layouts/layout';
import { type Session } from 'next-auth';
import { getCurrentUserProfile } from '@/app/auth/service';
import FollowUpNotifier from '@/app/enquiries/components/FollowUpNotifier';
import DuplicateLeadNotifier from '@/app/lead-routing/components/DuplicateLeadNotifier';
import { DefaultRoles } from '@/utills/constant';
import { RoleConfigProvider } from '@/context/role-config-provider';
import TrainingVideoGate from '@/components/trainingVideo/TrainingVideoGate';
import { useDispatch, useSelector } from 'react-redux';
import type { AppDispatch, RootState } from '@/store/store';
import { fetchFeatureControls } from '@/app/feature-control/slice';
import { useFeatureFlag } from '@/hooks/useFeatureFlag';

export default function AuthProvider({ children }: { children: React.ReactNode }) {
  const [auth, setAuth] = useState<string | boolean | undefined>();
  const [user, setUser] = useState<Session>();
  const dispatch: AppDispatch = useDispatch();
  const trainingVideoFeatureEnabled = useFeatureFlag('training-video');

  // Wait for the initial feature-control fetch before rendering the gate.
  const featureControlsStatus = useSelector(
    (state: RootState) => state.featureControls.status
  );
  const [hasLoadedFeatureControlsOnce, setHasLoadedFeatureControlsOnce] = useState(false);

  const isRefreshingTrainingStatusRef = useRef(false);

  useEffect(() => {
    if (
      featureControlsStatus === 'succeeded' ||
      featureControlsStatus === 'failed'
    ) {
      setHasLoadedFeatureControlsOnce(true);
    }
  }, [featureControlsStatus]);

  // Fetch feature controls after authentication.
  useEffect(() => {
    if (auth !== undefined && auth !== false) {
      dispatch(fetchFeatureControls());
    }
  }, [auth, dispatch]);

  // Refresh training status from the backend.
  const refreshTrainingStatus = useCallback(async(): Promise<void> => {
    if (!trainingVideoFeatureEnabled) return;
    if (isRefreshingTrainingStatusRef.current) return;

    isRefreshingTrainingStatusRef.current = true;

    try {
      const profileResponse = await getCurrentUserProfile();
      const profile = profileResponse.data;

      setUser((prev) =>
        prev === undefined
          ? prev
          : {
              ...prev,
              user: {
                ...prev.user,
                training_video_watched: profile.training_video_watched,
                training_video_progress: profile.training_video_progress,
                training_video_progress_detail:
                  profile.training_video_progress_detail,
              },
            }
      );

      // Sync the latest training status with the NextAuth session.
      try {
        const csrfToken = await getCsrfToken();

        await fetch('/api/auth/session', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            csrfToken,
            data: {
              training_video_watched: profile.training_video_watched,
              training_video_progress: profile.training_video_progress,
              training_video_progress_detail:
                profile.training_video_progress_detail,
            },
          }),
        });
      } catch (syncError) {
        console.error(
          'Error syncing training video status into session:',
          syncError
        );
      }
    } catch (error) {
      console.error('Error refreshing training video status:', error);
    } finally {
      isRefreshingTrainingStatusRef.current = false;
    }
  }, [trainingVideoFeatureEnabled]);

  // Keep the latest refresh function without re-running auth initialization.
  const refreshTrainingStatusRef = useRef(refreshTrainingStatus);
  refreshTrainingStatusRef.current = refreshTrainingStatus;

  // Initialize authentication.
  useEffect(() => {
    function setAuthenticate(): void {
      getSession()
        .then((getSess) => {
          if (getSess !== null) {
            axiosInstance.defaults.headers.common.authorization =
              `Bearer ${getSess.user.accessToken}`;

            setAuth(getSess.user.accessToken);
            setUser(getSess);

            void refreshTrainingStatusRef.current();
          } else {
            setAuth(false);
          }
        })
        .catch((error) => {
          console.error('Error getting session:', error);
          setAuth(false);
        });
    }

    setAuthenticate();
  }, []);

  // Set logged-in user role.
  const userRoleId = user?.user?.role?.id;

  // Roles that should receive follow-up notifications.
  const showFollowUpRoles = [
    DefaultRoles.team_lead.id,
    DefaultRoles.pre_sales.id,
    DefaultRoles.field_sales.id,
  ];

  const isNotificationVisible = showFollowUpRoles.includes(userRoleId!);

  if (auth !== undefined && auth !== false) {
    if (!hasLoadedFeatureControlsOnce) {
      return <div className="page-loading">Loading...</div>;
    }

    const needsTraining =
      trainingVideoFeatureEnabled &&
      user?.user?.training_video_watched === false;

    return (
      <SessionProvider session={user}>
        {needsTraining ? (
          <TrainingVideoGate
            onComplete={(updatedSession) => {
              setUser(updatedSession);
            }}
          />
        ) : (
          <RoleConfigProvider>
            <Layout>
              {isNotificationVisible && <FollowUpNotifier />}
              {isNotificationVisible && <DuplicateLeadNotifier />}
              {children}
            </Layout>
          </RoleConfigProvider>
        )}
      </SessionProvider>
    );
  }

  if (auth === false) {
    return <div>{children}</div>;
  }

  return <div className="page-loading">Loading...</div>;
}