import React, { Fragment, useEffect, useRef, useState } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import PropTypes from 'prop-types'
import useHasMounted from '@/hooks/useHasMounted'

export default function SessionTimeout ({ i18n, user, onTimeout, onCancelTimeout }) {
  const TIME = 30
  const hasMounted = useHasMounted()
  const countTimerRef = useRef()
  const [tick, setTick] = useState(0)
  const [countTimer, setCountTimer] = useState() // contador que lleva el control de tiempo en segundos para mostrar antes de cerrar sesion
  const [timerIsOn, setTimerIsOn] = useState(false) // verifica si el dialogo debe ser mostrado
  const idleTimer = useRef(null) // variable de control para el proceso de conteo

  // realiza el conteo regresivo
  const timedCount = () => {
    if (countTimerRef.current <= 0) {
      clearInterval(idleTimer.current)
      setTimerIsOn(false)
      setCountTimer(TIME)
      onTimeout()
      return
    }
    setCountTimer(countTimerRef.current - 1)
  }

  // inicia el conteo regresivo
  const startIdleMonitor = (expiracion = 0) => {
    if (expiracion < TIME * 1000) {
      countTimerRef.current = Math.round(expiracion / 1000) // tiempo restante
    } else {
      countTimerRef.current = TIME
    }
    setCountTimer(countTimerRef.current)
    setTimerIsOn(true)
    timedCount()
    idleTimer.current = setInterval(timedCount, 1000)
  }

  const calendarizeIdle = () => {
    // const fecha_inicio_sesion = new Date(user.fecha_inicio_sesion.slice(0, -1)) // uso de localtime quita Z al final del string
    const fecha_fin_sesion = new Date(user?.fecha_fin_sesion?.slice(0, -1)) // uso de localtime quita Z al final del string
    // const fecha_fin_sesion = new Date(user.fecha_fin_sesion)
    const expiracion = Math.round(fecha_fin_sesion.getTime() - (new Date()).getTime()) // valida cuando se realiza un F5 o reload del navegador (user.tiempo_expiracion * 60 * 1000)
    if (expiracion <= 0) {
      return // no debe calendarizar porque la sesion ya vencio
    }
    const timeInMillis = expiracion - (TIME * 1000)
    const processTimer = setTimeout(startIdleMonitor, timeInMillis > 0 ? timeInMillis : 0, expiracion)
    return () => clearTimeout(processTimer)
  }

  // cancela el conteo regresivo aumentando el tiempo de expiracion
  const stopIdleMonitor = async () => {
    await onCancelTimeout()
    clearInterval(idleTimer.current)
    setTimerIsOn(false)
    setCountTimer(TIME)
    // force rerender to update view
    setTick((tick) => tick + 1)
    // await new Promise(resolve => setTimeout(resolve, 2000)) // espera obligada para actualizacion DB
  }

  useEffect(() => {
    if (timerIsOn === false && tick > 0) {
      return calendarizeIdle()
    }
  }, [timerIsOn, tick])

  useEffect(() => {
    countTimerRef.current = countTimer
  }, [countTimer])

  useEffect(() => {
    if (!user || user === null) {
      if (idleTimer && idleTimer.current) {
        clearInterval(idleTimer.current)
      }
    }
    return () => clearInterval(idleTimer.current)
  }, [user])

  useEffect(() => {
    if (hasMounted) {
      return calendarizeIdle()
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [hasMounted])

  return (
    <>
      { timerIsOn && timerIsOn === true &&
        <Transition appear show as={Fragment}>
          <Dialog as='div' className='relative' style={{ zIndex: 999 }} onClose={() => { }}>
            <Transition.Child
              as={Fragment}
              enter='ease-out duration-300'
              enterFrom='opacity-0'
              enterTo='opacity-100'
              leave='ease-in duration-200'
              leaveFrom='opacity-100'
              leaveTo='opacity-0'
            >
              <div className='fixed inset-0 bg-black/25' />
            </Transition.Child>

            <div className='fixed inset-0 overflow-y-auto'>
              <div className='flex min-h-full items-center justify-center p-4 text-center'>
                <Transition.Child
                  as={Fragment}
                  enter='ease-out duration-300'
                  enterFrom='opacity-0 scale-95'
                  enterTo='opacity-100 scale-100'
                  leave='ease-in duration-200'
                  leaveFrom='opacity-100 scale-100'
                  leaveTo='opacity-0 scale-95'
                >
                  <Dialog.Panel className='w-full max-w-md overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all'>
                    <Dialog.Title
                      as='h3'
                      className='text-lg font-medium leading-6 text-gray-900'
                    >
                      {i18n.t('common.sessionToFinish')}
                    </Dialog.Title>
                    <div className='mt-2'>
                      <p className='text-lg font-extrabold text-gray-500'>
                        {countTimer}
                      </p>
                    </div>

                    <div className='mt-4 flex w-full flex-row-reverse'>
                      <button
                        type='button'
                        className='mr-2 inline-flex justify-center rounded-md border border-transparent bg-red-100 px-4 py-2 text-sm font-medium text-red-900 hover:bg-red-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2'
                        onClick={() => { stopIdleMonitor() }}
                      >
                        {i18n.t('common.sessionContinue')}
                      </button>
                    </div>
                  </Dialog.Panel>
                </Transition.Child>
              </div>
            </div>
          </Dialog>
        </Transition>
      }
    </>
  )
}

SessionTimeout.propTypes = {
  i18n: PropTypes.object,
  user: PropTypes.object,
  onTimeout: PropTypes.func,
  onCancelTimeout: PropTypes.func
}

SessionTimeout.defaultProps = {
  i18n: { t: () => { return 'txtNone' } },
  user: {},
  onTimeout: () => {},
  onCancelTimeout: () => {}
}
