import ExpiredConsentModal from 'components/Connection/ExpiredConsentModal/ExpiredConsentModal'
import { GrdfWaitConsentModal } from 'components/Connection/GRDFConnect/GrdfWaitConsent'
import Content from 'components/Content/Content'
import CustomPopupModal from 'components/CustomPopup/CustomPopupModal'
import DateNavigator from 'components/DateNavigator/DateNavigator'
import FluidChart from 'components/FluidChart/FluidChart'
import CozyBar from 'components/Header/CozyBar'
import Header from 'components/Header/Header'
import KonnectorViewerCard from 'components/Konnector/KonnectorViewerCard'
import KonnectorViewerList from 'components/Konnector/KonnectorViewerList'
import PartnerIssueModal from 'components/PartnerIssue/PartnerIssueModal'
import ReleaseNotesModal from 'components/ReleaseNotesModal/ReleaseNotesModal'
import { useClient } from 'cozy-client'
import { FluidState, FluidType, TimeStep } from 'enums'
import { DateTime } from 'luxon'
import React, { useCallback, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import DateChartService from 'services/dateChart.service'
import ProfileService from 'services/profile.service'
import {
  setCurrentIndex,
  setCurrentTimeStep,
  setSelectedDate,
  setShowOfflineData,
} from 'store/chart/chart.slice'
import { showReleaseNotes } from 'store/global/global.slice'
import { useAppDispatch, useAppSelector } from 'store/hooks'
import { openPartnersModal, setCustomPopup } from 'store/modal/modal.slice'
import { isLastDateReached } from 'utils/date'
import {
  getKonnectorUpdateError,
  getTodayDate,
  isKonnectorActive,
} from 'utils/utils'
import ConsumptionDetails from './ConsumptionDetails/ConsumptionDetails'
import FluidButtons from './FluidButtons/FluidButtons'

const ConsumptionView = ({ fluidType }: { fluidType: FluidType }) => {
  const navigate = useNavigate()
  const client = useClient()
  const dispatch = useAppDispatch()
  const isMulti = fluidType === FluidType.MULTIFLUID
  const {
    chart: { currentTimeStep, showOfflineData, selectedDate, currentIndex },
    global: { fluidStatus, releaseNotes },
    modal: { partnersIssueModal, customPopupModal },
  } = useAppSelector(state => state.ecolyo)

  const currentFluidStatus = fluidStatus[fluidType]
  const dateChartService = new DateChartService()

  const isWaitingForConsent =
    fluidType === FluidType.GAS &&
    currentFluidStatus.status === FluidState.CHALLENGE_ASKED

  const [waitConsent, setWaitConsent] = useState(isWaitingForConsent)
  const [openExpiredConsentModal, setOpenExpiredConsentModal] = useState(true)
  const [openReleaseNoteModal, setOpenReleaseNoteModal] = useState<boolean>(
    releaseNotes.show
  )
  const [consentExpiredFluids, setConsentExpiredFluids] = useState<FluidType[]>(
    []
  )

  /** Show wait consent modal when navigating and consent is "A valider" */
  useEffect(() => {
    setWaitConsent(isWaitingForConsent)
  }, [isWaitingForConsent])

  const updateKey =
    fluidType !== FluidType.MULTIFLUID && currentFluidStatus.lastDataDate
      ? `${currentFluidStatus.lastDataDate.toLocaleString()} + ${
          currentFluidStatus.status + fluidType
        }`
      : ''
  const lastDataDateKey =
    fluidType !== FluidType.MULTIFLUID && currentFluidStatus.lastDataDate
      ? `${currentFluidStatus.lastDataDate.toLocaleString() + fluidType}`
      : ''

  const getPartnerKey = (fluidType: FluidType): 'enedis' | 'egl' | 'grdf' => {
    switch (fluidType) {
      case FluidType.ELECTRICITY:
        return 'enedis'
      case FluidType.WATER:
        return 'egl'
      case FluidType.GAS:
        return 'grdf'
      default:
        throw new Error('unknown fluidtype')
    }
  }

  const handleCloseReleaseNoteModal = useCallback(() => {
    setOpenReleaseNoteModal(false)
    dispatch(
      showReleaseNotes({
        show: false,
        notes: releaseNotes.notes,
        redirectLink: releaseNotes.redirectLink,
      })
    )
    if (releaseNotes.redirectLink) {
      navigate(releaseNotes.redirectLink)
    }
  }, [dispatch, navigate, releaseNotes.notes, releaseNotes.redirectLink])

  const handleClosePartnerIssueModal = useCallback(
    async (fluidType: FluidType) => {
      const profileService = new ProfileService(client)
      const profileValues = await profileService.getProfile()
      if (profileValues) {
        const updatedProfile = await profileService.updateProfile({
          partnersIssueSeenDate: {
            ...profileValues.partnersIssueSeenDate,
            [getPartnerKey(fluidType)]: getTodayDate(),
          },
        })
        if (updatedProfile) {
          dispatch(
            openPartnersModal({
              ...partnersIssueModal,
              [getPartnerKey(fluidType)]: false,
            })
          )
        }
      }
    },
    [client, dispatch, partnersIssueModal]
  )

  const handleCloseCustomPopupModal = async () => {
    const profileService = new ProfileService(client)
    const updatedProfile = await profileService.updateProfile({
      customPopupDate: getTodayDate(),
    })
    if (updatedProfile) {
      dispatch(
        setCustomPopup({
          ...customPopupModal,
          popupEnabled: false,
        })
      )
    }
  }

  useEffect(
    /** Reset half-hour timestep for water & gas & multifluid */
    function setDefaultTimeStep() {
      if (
        fluidType !== FluidType.ELECTRICITY &&
        currentTimeStep == TimeStep.HALF_AN_HOUR
      ) {
        dispatch(setCurrentTimeStep(TimeStep.WEEK))
      }
    },
    [dispatch, fluidType, currentTimeStep]
  )

  /**
   * If fluid is not connected, display Connect components
   * If fluid is connected, dispatch FluidChart
   */
  useEffect(() => {
    const isFluidConnected = isKonnectorActive(fluidStatus, fluidType)
    dispatch(setShowOfflineData(isFluidConnected))
  }, [dispatch, fluidStatus, fluidType])

  /** Check if some fluids have expired consent error */
  useEffect(() => {
    let subscribed = true
    const expiredConsents: FluidType[] = []
    for (const fluid of fluidStatus) {
      const error = fluid.connection.triggerState?.last_error
      if (error && getKonnectorUpdateError(error) === 'error_update_oauth') {
        expiredConsents.push(fluid.fluidType)
      }
    }

    if (subscribed) setConsentExpiredFluids(expiredConsents)
    return () => {
      subscribed = false
    }
  }, [fluidStatus])

  const disablePrev =
    selectedDate <
      DateTime.local(0, 1, 1).setZone('utc', {
        keepLocalTime: true,
      }) && !isKonnectorActive(fluidStatus, FluidType.MULTIFLUID)

  const getIncrement = (next: boolean) =>
    next
      ? dateChartService.defineIncrementForNextIndex(
          currentTimeStep,
          selectedDate,
          currentIndex
        )
      : dateChartService.defineIncrementForPreviousIndex(
          currentTimeStep,
          selectedDate,
          currentIndex
        )

  const handleClickMove = (next: boolean) => {
    const increment = getIncrement(next)
    const updatedDate = dateChartService.incrementDate(
      currentTimeStep,
      selectedDate,
      increment
    )
    const updatedIndex = dateChartService.defineDateIndex(
      currentTimeStep,
      updatedDate
    )
    dispatch(setSelectedDate(updatedDate))
    dispatch(setCurrentIndex(updatedIndex))
  }

  return (
    <>
      <CozyBar titleKey="common.title_consumption" />
      <Header desktopTitleKey="common.title_consumption">
        <DateNavigator
          disableNext={isLastDateReached(selectedDate, currentTimeStep)}
          disablePrev={disablePrev}
          handleNextDate={() => handleClickMove(true)}
          handlePrevDate={() => handleClickMove(false)}
          navigatorDate={selectedDate}
          timeStep={currentTimeStep}
        />
      </Header>
      <Content>
        <FluidButtons activeFluid={fluidType} key={updateKey} />

        {showOfflineData && (
          <>
            <FluidChart fluidType={fluidType} key={lastDataDateKey} />
            <ConsumptionDetails fluidType={fluidType} />
          </>
        )}
        {/* TODO maybe move this inside block above  */}
        {!isMulti && <KonnectorViewerCard fluidType={fluidType} />}

        {isMulti && !showOfflineData && <KonnectorViewerList />}
      </Content>

      {/* MODALS */}
      {openReleaseNoteModal && (
        <ReleaseNotesModal
          open={openReleaseNoteModal}
          handleCloseClick={handleCloseReleaseNoteModal}
        />
      )}
      {/* Partner issue modals for individual fluids */}
      {fluidStatus
        .filter(fluid => fluid.maintenance)
        .filter(fluid => fluid.fluidType === fluidType)
        .map(issuedFluid => (
          <PartnerIssueModal
            key={issuedFluid.fluidType}
            issuedFluid={issuedFluid.fluidType}
            open={partnersIssueModal[getPartnerKey(issuedFluid.fluidType)]}
            handleCloseClick={handleClosePartnerIssueModal}
          />
        ))}
      <CustomPopupModal
        customPopup={customPopupModal}
        handleCloseClick={handleCloseCustomPopupModal}
      />
      {Boolean(consentExpiredFluids.length) &&
        consentExpiredFluids.map(fluid => (
          <ExpiredConsentModal
            key={fluid}
            open={openExpiredConsentModal}
            handleCloseClick={() => setOpenExpiredConsentModal(false)}
            fluidType={fluid}
            toggleModal={() => setOpenExpiredConsentModal(prev => !prev)}
          />
        ))}

      {/* GRDF Waiting screen */}
      <GrdfWaitConsentModal open={waitConsent} setOpen={setWaitConsent} />
    </>
  )
}

export default ConsumptionView