import React, { useEffect, useState } from 'react'
import {
  Col,
  DatePicker,
  Form,
  FormInstance,
  Radio,
  RadioChangeEvent,
  Row,
  TimePicker
} from 'antd'

import { Moment } from 'moment'
import moment from 'moment-timezone'

import { Paragraph } from 'components/Typography'
import { Text } from 'components/Typography'
import { InfoSection } from '../../components/InfoSection'

import { MultistageFormStage } from 'components/MultistageForm'
import { MultistageFormStageProps } from 'components/MultistageForm/MultistageFormStage'

import { Timezone } from 'components/TimezoneSelect/utilities/timezone'
import { TimezoneSelect } from 'components/TimezoneSelect'
import { isDisabledDate } from 'components/PreReleaseModal/utilities/isDisabledDate'

import { ReactComponent as DateIcon } from 'icons/date.svg'
import { ReactComponent as DownIcon } from 'icons/down.svg'

import { MusicItem } from 'models/talent/talent-profile-module.model'

import './SmartItemReleaseForm.scss'
import { Maybe } from 'types/utilities'
import { MusicReleaseScope } from '@komi-app/shared-types'

export interface SmartItemReleaseFormProps extends MultistageFormStageProps {
  isEdit: boolean
  music?: MusicItem
}

const guessedTz = moment.tz.guess()

const getUtcDateDayDiff = (firstDate: Moment, secondDate: Moment) => {
  const utcFirstDate = firstDate
  const utcSecondDate = secondDate

  return utcSecondDate.diff(utcFirstDate, 'd')
}
const getDisabledHours = (date: Moment) => {
  const dateTz = date.tz()

  const nowOffset = dateTz ? moment.tz(dateTz) : moment()
  // Subtract one day to fix off by one error that causes hours to be disabled on both today and tomorrow.
  const daysUntilRelease = date.diff(nowOffset.add(-1, 'd'), 'd')

  // If it's zero, laden the disabled hours
  const hours = []
  if (daysUntilRelease === 0) {
    for (let i = 0; i < nowOffset.hour(); i++) {
      hours.push(i)
    }
  }

  return hours
}
const getDisabledMinutes = (hour: number) => {
  const minutes = []

  if (hour === moment().hour()) {
    for (let i = 0; i < moment().minute(); i++) {
      minutes.push(i)
    }
  }
  return minutes
}

export const SmartItemReleaseForm: React.FC<SmartItemReleaseFormProps> = ({
  accumulativeFormState,
  music,
  ...props
}) => {
  const [form, setForm] = useState<FormInstance>()

  const [timezone, setTimezone] = useState<string>(guessedTz)
  const [releaseScope, setReleaseScope] = useState<MusicReleaseScope>(
    MusicReleaseScope.LOCAL
  )
  const [disabledHours, setDisabledHours] = useState<number[]>([])

  const [showInfo, setShowInfo] = useState(true)

  const [date, setDate] = useState<Maybe<Moment>>(undefined)
  const [time, setTime] = useState<Maybe<Moment>>(undefined)

  useEffect(() => {
    form?.setFieldsValue({
      releaseDate: date
    })
  }, [date])

  useEffect(() => {
    form?.setFieldsValue({
      releaseTime: time?.clone(),
      releaseDate: date?.clone()
    })

    if (date) {
      const disabledHours = getDisabledHours(date)
      setDisabledHours(disabledHours)
    }
  }, [date, time])

  const initialValues = React.useMemo(() => {
    const timezone =
      accumulativeFormState.timezone || music?.timezone || guessedTz
    const releaseScope =
      accumulativeFormState.releaseScope ||
      music?.releaseScope ||
      MusicReleaseScope.LOCAL

    setTimezone(timezone)
    setReleaseScope(releaseScope)

    const releaseDate =
      accumulativeFormState.releaseDate || music?.releaseDate || undefined
    const releaseTime =
      accumulativeFormState.releaseTime || music?.releaseDate || undefined
    const releaseDateMoment = releaseDate ? moment(releaseDate) : undefined

    let releaseTimeMoment: Maybe<Moment>
    if (releaseTime) {
      releaseTimeMoment =
        MusicReleaseScope.LOCAL === releaseScope
          ? moment(releaseTime).utc()
          : moment.tz(releaseTime, timezone)
    }

    // Dishonourable hotfix: this creates a synchronous setState, required for edits
    setTimeout(() => setTime(releaseTimeMoment))
    setTimeout(() => setDate(releaseDateMoment))

    const disabledHours = releaseDateMoment
      ? getDisabledHours(releaseDateMoment)
      : []
    setDisabledHours(disabledHours)

    return {
      releaseDate: releaseDateMoment,
      releaseTime: releaseTimeMoment,
      releaseScope,
      timezone
    }
  }, [])

  const handleReleaseTypeChange = (event: RadioChangeEvent) => {
    setReleaseScope(event.target.value)
  }

  const handleInfoClose = () => {
    setShowInfo(false)
  }

  const handleTimeChange = (pickedTime: Moment) => {
    const tzAdjustedPickedTime = MusicReleaseScope.LOCAL
      ? moment().utc().set({
          hour: pickedTime.hour(),
          minute: pickedTime.minute(),
          second: pickedTime.second()
        })
      : pickedTime.clone()

    setTime(tzAdjustedPickedTime)
  }

  const handleDateChange = (pickedDate: Moment) => {
    const utcPickedDate = pickedDate.tz(timezone).clone()
    setDate(utcPickedDate)

    const disabledHours = getDisabledHours(utcPickedDate)
    setDisabledHours(disabledHours)

    // Reset time if the date and time are earlier than present
    const now = moment.tz(timezone)

    // If it's any time in the future, bail out
    const isFutureDay = getUtcDateDayDiff(now, utcPickedDate) > 0
    const isFutureHour = now.hours() > utcPickedDate.hours()
    const isFutureMinute = now.minutes() > utcPickedDate.minutes()

    if (isFutureDay || isFutureHour || isFutureMinute) {
      return
    }

    setDate(now)
    setTime(now)
  }

  const handleTimezoneSelect = (timezone: Timezone) => {
    setTimezone(timezone.primaryName)

    setDate(date?.tz(timezone.primaryName).clone())
    setTime(time?.tz(timezone.primaryName).clone())
  }

  const handleTimezoneChange = (timezone: Maybe<Timezone>) => {
    form?.setFieldsValue({ timezone: timezone?.primaryName })
  }

  return (
    <MultistageFormStage
      requiredMark="optional"
      initialValues={initialValues}
      setForm={setForm}
      validateTrigger="onSubmit"
      {...props}
    >
      <Paragraph preset="semibold18" className="p__b--12">
        Release type
      </Paragraph>

      <Form.Item name="releaseScope">
        <Radio.Group
          onChange={handleReleaseTypeChange}
          value={releaseScope}
          className="smart-release--type-radio-group"
        >
          <Radio value={MusicReleaseScope.LOCAL}>
            <Text preset="regular12" className="text--default opacity--80">
              Local release time
            </Text>
          </Radio>

          <Radio value={MusicReleaseScope.GLOBAL}>
            <Text preset="regular12" className="text--default opacity--80">
              Global release time
            </Text>
          </Radio>
        </Radio.Group>
      </Form.Item>

      {showInfo && (
        <Row
          data-testid="smart-release--info"
          className="smart-release--type-info"
        >
          <InfoSection title="How it works" showClose onClose={handleInfoClose}>
            Your Pre-Save will convert at the release time you have set in the
            appropriate timezones
          </InfoSection>
        </Row>
      )}

      <Row gutter={34}>
        <Col span={12}>
          <Form.Item
            className={'m__b--24'}
            label="Release date"
            labelAlign="left"
            name="releaseDate"
            rules={[{ required: true, message: 'Please pick a release date' }]}
          >
            <DatePicker
              value={date}
              onSelect={handleDateChange}
              disabledDate={(date: Moment) =>
                isDisabledDate(date || moment().tz(timezone))
              }
              placeholder="Date"
              format="DD MMMM, YYYY"
              allowClear={false}
              suffixIcon={<DateIcon />}
              getPopupContainer={trigger =>
                trigger.parentElement || document.body
              }
            />
          </Form.Item>
        </Col>

        <Col span={12}>
          <Form.Item
            label="Release time"
            labelAlign="left"
            name="releaseTime"
            rules={[
              { required: true, message: 'Please select a release time' }
            ]}
          >
            <TimePicker
              value={time}
              onSelect={handleTimeChange}
              disabledHours={() => disabledHours}
              disabledMinutes={getDisabledMinutes}
              placeholder="12:00"
              format={'HH:mm'}
              allowClear={false}
              suffixIcon={<DownIcon />}
              getPopupContainer={trigger =>
                trigger.parentElement || document.body
              }
            />
          </Form.Item>
        </Col>
      </Row>

      {releaseScope === MusicReleaseScope.GLOBAL && (
        <Row>
          <Paragraph className="m__b--8 m__t--32" preset="regular14">
            Timezone
          </Paragraph>
          <Form.Item
            className="smart-release--timezone"
            name="timezone"
            shouldUpdate
            rules={[{ required: true, message: 'Please select a timezone' }]}
            labelCol={{ span: 24 }}
            wrapperCol={{ span: 24 }}
            style={{ width: '100%' }}
          >
            <TimezoneSelect
              form={form}
              initialValue={timezone}
              date={date || moment()}
              handleSelect={handleTimezoneSelect}
              handleChange={handleTimezoneChange}
            />
          </Form.Item>
        </Row>
      )}
    </MultistageFormStage>
  )
}
