import React, {
  createContext,
  useContext,
  useEffect,
  useMemo,
  useState
} from 'react'

import useUrlState from '@ahooksjs/use-url-state'
import { LeftCircleOutlined } from '@ant-design/icons'
import { Button, Select, message, Skeleton, DatePicker } from 'antd'
import moment from 'moment-timezone'
import { RangeValue } from 'rc-picker/lib/interface'
import { useNavigate, useParams } from 'react-router-dom'
import useSWR, { useSWRConfig } from 'swr'

import {
  getClusterInfo,
  createComparisonReport,
  getClusterDataInfo
} from '~/api'
import { comparisonReportTelemetry } from '~/telemetry/comparison-report'
import { globalAddTranslations } from '~/translations'
import { formatDateTime } from '~/utils/date-time'
import { CloudUIProvider, OnPremUIProvider } from '~/utils/tenant-type'

import comparisonTranslations, { COMPARISON_REPORT_NS } from '../translations'
import { ReportTable, getComparisonReportListKey } from './ReportTable'

// Add local translations for comparison report
globalAddTranslations(comparisonTranslations, COMPARISON_REPORT_NS)

interface TouchReportFormValue {
  recent?: number
  packageId?: string
  startTime?: number
  endTime?: number
}
const initialFormValues = (): TouchReportFormValue => ({
  recent: 0,
  packageId: '',
  startTime: 0,
  endTime: 0
})
type TouchReportForm = { t1: TouchReportFormValue; t2: TouchReportFormValue }
const FormContext = createContext<
  [TouchReportForm, React.Dispatch<React.SetStateAction<TouchReportForm>>]
>(null as any)
const useFormInstance = () => useContext(FormContext)

const Page: React.FC = () => {
  const { orgId, cid } = useParams<'orgId' | 'cid'>()
  const navigate = useNavigate()
  const [queryParams] = useUrlState({
    from: '',
    to: ''
  })
  const f = useState<TouchReportForm>(() => {
    if (queryParams.from !== '' && queryParams.to !== '') {
      return {
        t1: {
          ...initialFormValues(),
          startTime: Number(queryParams.from),
          endTime: Number(queryParams.to)
        },
        t2: initialFormValues()
      }
    }
    return {
      t1: initialFormValues(),
      t2: initialFormValues()
    }
  })
  const { data: clusterInfoRes } = useSWR(
    `/orgs/${orgId}/clusters/${cid}`,
    () => getClusterInfo(orgId!, cid!)
  )

  return (
    <div className='flex flex-col h-full'>
      <div className='py-4'>
        <Button
          icon={<LeftCircleOutlined />}
          type='text'
          onClick={() => navigate(-1)}
        ></Button>
        <span className='text-xl ml-2'>Comparison Report</span>
      </div>

      <div className='rounded-lg bg-white p-6 mb-4'>
        <p className='text-xl'>
          Cluster Name:{' '}
          {clusterInfoRes?.data?.name ? (
            clusterInfoRes?.data?.name
          ) : (
            <Skeleton.Input style={{ width: '150px' }} active />
          )}
        </p>

        <div className='relative'>
          <FormContext.Provider value={f}>
            <OnPremUIProvider>
              <OPTimerangeSelect />
            </OnPremUIProvider>
            <CloudUIProvider>
              <CloudTimerangeSelect />
            </CloudUIProvider>
            <CreateReportButton />
          </FormContext.Provider>
        </div>
      </div>

      <div className='rounded-lg bg-white px-6 pt-6'>
        <p className='text-lg'>All Reports</p>
        <ReportTable />
      </div>
    </div>
  )
}

const CreateReportButton = React.memo(() => {
  const { orgId, cid } = useParams<'orgId' | 'cid'>()
  const [f] = useFormInstance()
  const { mutate } = useSWRConfig()
  const [loading, setLoading] = useState(false)

  return (
    <Button
      style={{ position: 'absolute !important' as any }}
      className='absolute top-0 right-0'
      type='primary'
      disabled={loading}
      onClick={async () => {
        const isValidForm =
          (f.t1.packageId || (f.t1.startTime && f.t1.endTime) || f.t1.recent) &&
          (f.t2.packageId || (f.t2.startTime && f.t2.endTime) || f.t2.recent)
        if (!isValidForm) {
          message.error('Please select valid time range')
          return
        }

        try {
          setLoading(true)
          const now = Math.floor(Date.now() / 1000)
          const endTime1 = f.t1.recent ? now : f.t1.endTime!
          const startTime1 = f.t1.recent
            ? endTime1 - f.t1.recent * 60
            : f.t1.startTime
          const endTime2 = f.t2.recent ? now : f.t2.endTime!
          const startTime2 = f.t2.recent
            ? endTime2 - f.t2.recent * 60
            : f.t2.startTime
          const isValidTime = endTime1 <= now && endTime2 <= now
          if (!isValidTime) {
            message.error(
              'Please select the time range less than the current time'
            )
            return
          }

          const params = {
            startTime1,
            startTime2,
            endTime1,
            endTime2,
            packageID1: f.t1.packageId ? [f.t1.packageId!] : (null as any),
            packageID2: f.t2.packageId ? [f.t2.packageId!] : (null as any)
          }
          await createComparisonReport(orgId!, cid!, params)
          mutate(getComparisonReportListKey(orgId!, cid!, 1))
          comparisonReportTelemetry.createReport(orgId!, cid!, params)
          message.loading(
            'Diagnosis Engine is generating report, it may take about few minutes.'
          )
        } finally {
          setLoading(false)
        }
      }}
    >
      Create Report
    </Button>
  )
})

const disabledDate: (date: moment.Moment) => boolean = (current) => {
  const biggerThanNow = current && current > moment().endOf('days')
  return biggerThanNow
}

enum OPSelectionItem {
  Package = 'package',
  Absolute = 'absolute'
}
const OpSelections: { label: string; value: OPSelectionItem }[] = [
  { label: 'By Package', value: OPSelectionItem.Package },
  { label: 'Absolute', value: OPSelectionItem.Absolute }
]

const OPTimerangeSelect = () => {
  const { orgId, cid } = useParams<'orgId' | 'cid'>()
  const [f, setF] = useFormInstance()
  const [t1Type, setT1Type] = useState<OPSelectionItem>(OPSelectionItem.Package)
  const [t2Type, setT2Type] = useState<OPSelectionItem>(OPSelectionItem.Package)

  const { data: packagesRes, error } = useSWR(
    `/orgs/${orgId}/clusters/${cid}/data`,
    () => getClusterDataInfo(orgId!, cid!)
  )
  const loading = !packagesRes || !!error
  const packages = useMemo(
    () => packagesRes?.data?.dataInfos || [],
    [packagesRes]
  )

  return (
    <>
      <div className='mb-2'>
        <span className='mr-2'>T1 Range:</span>
        <Select
          className='mr-2'
          style={{ width: 120 }}
          defaultValue={t1Type}
          onChange={(v) => {
            setT1Type(v)
            setF((prev) => ({ ...prev, t1: initialFormValues() }))
          }}
        >
          {OpSelections.map((item) => (
            <Select.Option key={item.value} value={item.value}>
              {item.label}
            </Select.Option>
          ))}
        </Select>
        {t1Type === OPSelectionItem.Package &&
          (loading ? (
            <Skeleton.Input active style={{ width: 380 }} />
          ) : (
            <Select
              allowClear
              className='mr-2'
              style={{ width: 380 }}
              placeholder='Please select a time range'
              onChange={(v) => {
                const pkg = packages.find((p) => p.itemID === v)!
                setF((prev) => ({
                  ...prev,
                  t1: {
                    ...prev.t1,
                    packageId: v,
                    startTime: pkg.startTime,
                    endTime: pkg.endTime
                  }
                }))
              }}
            >
              {packages.map((p) => (
                <Select.Option
                  key={p.itemID}
                  value={p.itemID}
                  disabled={p.itemID === f.t2.packageId}
                >
                  {formatDateTime(p.startTime!)} ~ {formatDateTime(p.endTime!)}
                </Select.Option>
              ))}
            </Select>
          ))}
        {t1Type === OPSelectionItem.Absolute && (
          <DatePicker.RangePicker
            className='rounded-lg'
            showTime
            onChange={(v) => {
              const [start, end] = v!.map((t) => t!.unix())
              setF((prev) => ({
                ...prev,
                t1: { ...prev.t1, startTime: start, endTime: end }
              }))
            }}
          />
        )}
      </div>

      <div className='mb-2'>
        <span className='mr-2'>T2 Range:</span>
        <Select
          className='mr-2'
          style={{ width: 120 }}
          defaultValue={t2Type}
          onChange={(v) => {
            setT2Type(v)
            setF((prev) => ({ ...prev, t2: initialFormValues() }))
          }}
        >
          {OpSelections.map((item) => (
            <Select.Option key={item.value} value={item.value}>
              {item.label}
            </Select.Option>
          ))}
        </Select>
        {t2Type === OPSelectionItem.Package &&
          (loading ? (
            <Skeleton.Input active style={{ width: 380 }} />
          ) : (
            <Select<string>
              allowClear
              className='mr-2'
              style={{ width: 380 }}
              placeholder='Please select a time range'
              onChange={(v) => {
                const pkg = packages.find((p) => p.itemID === v)!
                setF((prev) => ({
                  ...prev,
                  t2: {
                    ...prev.t2,
                    packageId: v,
                    startTime: pkg.startTime,
                    endTime: pkg.endTime
                  }
                }))
              }}
            >
              {packages.map((p) => (
                <Select.Option
                  key={p.itemID}
                  value={p.itemID}
                  disabled={p.itemID === f.t1.packageId}
                >
                  {formatDateTime(p.startTime!)} ~ {formatDateTime(p.endTime!)}
                </Select.Option>
              ))}
            </Select>
          ))}
        {t2Type === OPSelectionItem.Absolute && (
          <DatePicker.RangePicker
            showTime
            className='rounded-lg'
            disabledDate={disabledDate}
            onChange={(v) => {
              const [start, end] = v!.map((t) => t!.unix())
              setF((prev) => ({
                ...prev,
                t2: { ...prev.t2, startTime: start, endTime: end }
              }))
            }}
          />
        )}
      </div>
    </>
  )
}

enum CloudSelectionItem {
  Absolute = 'absolute',
  Recent30Min = 30
}
const CloudSelections: { label: string; value: CloudSelectionItem }[] = [
  { label: 'Absolute', value: CloudSelectionItem.Absolute },
  { label: 'Recent 30 min', value: CloudSelectionItem.Recent30Min }
]

const CloudTimerangeSelect = () => {
  const [f, setF] = useFormInstance()
  const [t2Type, setT2Type] = useState(CloudSelectionItem.Recent30Min)

  const [hackValue] = useState<RangeValue<moment.Moment>>(() => {
    if (f.t1.startTime! > 0) {
      return [moment.unix(f.t1.startTime!), moment.unix(f.t1.endTime!)]
    }
    return null
  })

  useEffect(() => {
    setF((prev) => ({
      ...prev,
      t2: { ...prev.t2, recent: CloudSelectionItem.Recent30Min as number }
    }))
  }, [setF])

  return (
    <>
      <div className='mb-2'>
        <span className='mr-2'>T1 Range:</span>
        <Select
          value={CloudSelectionItem.Absolute}
          className='mr-2'
          style={{ width: 150 }}
        >
          <Select.Option
            key={CloudSelectionItem.Absolute}
            value={CloudSelectionItem.Absolute}
          >
            Absolute
          </Select.Option>
        </Select>
        <DatePicker.RangePicker
          defaultValue={hackValue}
          showTime
          className='rounded-lg'
          disabledDate={disabledDate}
          onChange={(v) => {
            const [start, end] = v!.map((t) => t!.unix())
            setF((prev) => ({
              ...prev,
              t1: { ...prev.t1, startTime: start, endTime: end }
            }))
          }}
        />
      </div>

      <div className='mb-2'>
        <span className='mr-2'>T2 Range:</span>
        <Select
          className='mr-2'
          style={{ width: 150 }}
          defaultValue={t2Type}
          onChange={(v) => {
            if (v === CloudSelectionItem.Recent30Min) {
              setF((prev) => ({
                ...prev,
                t2: {
                  ...initialFormValues(),
                  recent: CloudSelectionItem.Recent30Min as number
                }
              }))
            }
            setT2Type(v)
          }}
        >
          {CloudSelections.map((item) => (
            <Select.Option key={item.value} value={item.value}>
              {item.label}
            </Select.Option>
          ))}
        </Select>
        {t2Type === CloudSelectionItem.Absolute && (
          <DatePicker.RangePicker
            showTime
            className='rounded-lg'
            disabledDate={disabledDate}
            onChange={(v) => {
              const [start, end] = v!.map((t) => t!.unix())
              setF((prev) => ({
                ...prev,
                t2: { ...prev.t2, recent: 0, startTime: start, endTime: end }
              }))
            }}
          />
        )}
      </div>
    </>
  )
}

export default Page
