"use client"

import { usePathname } from "next/navigation"
import {
  startTransition,
  useEffect,
  useOptimistic,
  useRef,
  useState,
} from "react"

import useRouterTransitionStore from "@/stores/router-transition"
import useTrackingStore from "@/stores/tracking"

import { useSessionId } from "@/hooks/useSessionId"
import { createSDKPageObject, pushToDataLayer } from "@/utils/tracking"

import type { TrackingSDKProps } from "@/types/components/tracking"

enum TransitionStatusEnum {
  NotRun = "NotRun",
  Running = "Running",
  Done = "Done",
}

type TransitionStatus = keyof typeof TransitionStatusEnum

export default function RouterTransition({
  pageData,
  userData,
  hotelInfo,
  paymentInfo,
}: TrackingSDKProps) {
  const [loading, setLoading] = useOptimistic(false)
  const [status, setStatus] = useState<TransitionStatus>(
    TransitionStatusEnum.NotRun
  )
  const { getPageLoadTime, hasRun, setHasRun } = useTrackingStore()

  const sessionId = useSessionId()
  const pathName = usePathname()
  const { isTransitioning, stopRouterTransition } = useRouterTransitionStore()

  const previousPathname = useRef<string | null>(null)

  // We need this check to differentiate hard vs soft navigations
  // This is not because of StrictMode
  const hasRunInitial = useRef<boolean>(false)

  useEffect(() => {
    if (!hasRun && !hasRunInitial.current) {
      const perfObserver = new PerformanceObserver((observedEntries) => {
        const entry = observedEntries.getEntriesByType("navigation")[0]
        if (entry) {
          const trackingData = {
            ...pageData,
            sessionId,
            pathName,
            pageLoadTime: entry.duration / 1000,
          }
          const pageObject = createSDKPageObject(trackingData)
          pushToDataLayer({
            event: "pageView",
            pageInfo: pageObject,
            userInfo: userData,
            hotelInfo: hotelInfo,
            paymentInfo,
          })

          perfObserver.disconnect()
        }
      })
      perfObserver.observe({
        type: "navigation",
        buffered: true,
      })
      hasRunInitial.current = true
      setHasRun()
    }
  }, [
    pathName,
    hasRun,
    setHasRun,
    hotelInfo,
    userData,
    pageData,
    sessionId,
    paymentInfo,
  ])

  useEffect(() => {
    if (isTransitioning && status === TransitionStatusEnum.NotRun) {
      startTransition(() => {
        setStatus(TransitionStatusEnum.Running)
        setLoading(true)
      })
    } else if (
      !loading &&
      isTransitioning &&
      status === TransitionStatusEnum.Running
    ) {
      setStatus(TransitionStatusEnum.Done)
      stopRouterTransition()
    } else if (
      !loading &&
      !isTransitioning &&
      status === TransitionStatusEnum.Done
    ) {
      if (hasRun && !hasRunInitial.current) {
        const trackingData = {
          ...pageData,
          sessionId,
          pathName,
          pageLoadTime: getPageLoadTime(),
        }
        const pageObject = createSDKPageObject(trackingData)
        if (previousPathname.current !== pathName) {
          pushToDataLayer({
            event: "pageView",
            pageInfo: pageObject,
            userInfo: userData,
            hotelInfo: hotelInfo,
            paymentInfo,
          })
        }
        previousPathname.current = pathName // Update for next render
      }
    }
  }, [
    isTransitioning,
    loading,
    status,
    setLoading,
    stopRouterTransition,
    pageData,
    pathName,
    userData,
    hotelInfo,
    getPageLoadTime,
    hasRun,
    sessionId,
    paymentInfo,
  ])

  return null
}
