import React, { MutableRefObject, useEffect, useRef, useState } from 'react'

import {
  ReloadOutlined,
  LoadingOutlined,
  QuestionOutlined,
  ExclamationCircleOutlined,
  QuestionCircleOutlined
} from '@ant-design/icons'
import {
  Button,
  Table,
  Tag,
  TableColumnsType,
  Modal,
  Tooltip,
  Skeleton,
  Space,
  Popconfirm,
  Typography
} from 'antd'
import { ModalFunc } from 'antd/lib/modal/confirm'
import { AxiosError, AxiosResponse } from 'axios'
import { useParams, Link } from 'react-router-dom'
import useSWR, { KeyedMutator } from 'swr'

import { ReportListReportResponse, ReportReportOverview } from '@clinic/client'
import { getReportList, deleteReport, getReport } from '~/api'
import { ReportArgs } from '~/pages/reports/shared/types'
import { reportsTelemetry } from '~/telemetry/reports'
import { formatDateTime } from '~/utils/date-time'

import { useReportTypeAPIPrefix, useReportTypeName } from './useReportType'

const { Text } = Typography

enum StatusType {
  Unscheduled = 'unscheduled',
  Running = 'running',
  Success = 'success',
  Failed = 'failed',
  Deleted = 'deleted',
  Pending = 'pending'
}
const tagColorMap: { [k: string]: string } = {
  [StatusType.Running]: 'processing',
  [StatusType.Pending]: 'processing',
  [StatusType.Success]: 'success',
  [StatusType.Failed]: 'error'
}

const PAGE_SIZE = 10

export const getListKey = (
  oid: string,
  cid: string,
  reportType: string,
  page: number
) => ['reports/list', oid, cid, reportType, page]

export const ReportTable: React.FC = () => {
  const { orgId, cid } = useParams<'orgId' | 'cid'>()
  const apiPrefix = useReportTypeAPIPrefix()
  const [page, setPage] = useState(1)
  const {
    data: listRes,
    error,
    mutate
  } = useSWR(getListKey(orgId!, cid!, apiPrefix, page), () =>
    getReportList(orgId!, cid!, apiPrefix, PAGE_SIZE, page)
  )
  const modalRef: MutableRefObject<ReturnType<ModalFunc> | null> = useRef(null)
  const title = useReportTypeName()

  useAutoRefresh(mutate, listRes?.data?.reports)

  const columns: TableColumnsType<ReportReportOverview> = [
    {
      title: 'Time Range',
      key: 'timerange',
      width: 200,
      render: (val, rec) => (
        <>
          <p className='mb-0'>
            {formatDateTime((rec.args as ReportArgs)?.begin_ts!)} ~
          </p>
          <p className='mb-0'>
            {formatDateTime((rec.args as ReportArgs)?.end_ts!)}
          </p>
        </>
      )
    },
    {
      title: 'Creator',
      dataIndex: 'creator',
      render: (val) => (
        <Text style={{ width: 180 }} ellipsis={{ tooltip: val }}>
          {val}
        </Text>
      )
    },
    {
      title: 'Created At',
      dataIndex: 'createdAt',
      width: 200,
      render: (val) => <p className='mb-0'>{formatDateTime(val)}</p>
    },
    {
      title: 'Status',
      dataIndex: 'status',
      width: 140,
      render: (val: StatusType, rec) => (
        <>
          <Tag className='rounded-lg' color={tagColorMap[val] || 'default'}>
            {`${val.slice(0, 1).toUpperCase()}${val.slice(1)}`}
          </Tag>
          {(val === StatusType.Running || val === StatusType.Pending) && (
            <Tooltip placement='bottom' title='Refresh Status'>
              <Button
                size='small'
                shape='circle'
                icon={<ReloadOutlined />}
                onClick={() => mutate()}
              />
            </Tooltip>
          )}
          {val === StatusType.Failed && (
            <Button
              size='small'
              shape='circle'
              icon={<QuestionOutlined />}
              onClick={async () => {
                const modal = Modal.error({
                  title: 'Error',
                  content: <Skeleton.Input style={{ width: '150px' }} active />,
                  icon: <LoadingOutlined />,
                  okText: 'Close',
                  maskClosable: true,
                  afterClose: () => (modalRef.current = null)
                })
                modalRef.current = modal

                try {
                  const { data } = await getReport(
                    orgId!,
                    cid!,
                    String(rec.report_id!)
                  )
                  modal.update({
                    content:
                      (data?.data as any)?.errorMessage || 'No error message',
                    icon: <ExclamationCircleOutlined />
                  })
                } catch (e) {
                  modal.update({
                    content:
                      (e as AxiosError).response?.data.message ||
                      'No error message',
                    icon: <ExclamationCircleOutlined />
                  })
                }
              }}
            />
          )}
        </>
      )
    },
    {
      title: 'Operations',
      key: 'ops',
      render: (val, rec, idx) => {
        return (
          <Space>
            <Link
              // hack for styles
              // react-router-dom `Link` does not support `disabled` prop but antd global style works
              {...{ disabled: rec.status !== StatusType.Success }}
              className='mr-2 select-none'
              to={`${rec.report_id}`}
              target='_blank'
              onClick={(e) => {
                reportsTelemetry.viewReport(title, {
                  orgId: orgId!,
                  clusterId: cid!,
                  reportId: rec.report_id!
                })
                rec.status !== StatusType.Success && e.preventDefault()
              }}
            >
              View
            </Link>

            {(rec.status === StatusType.Success ||
              rec.status === StatusType.Failed) && (
              <Popconfirm
                onConfirm={async () => {
                  await deleteReport(orgId!, cid!, String(rec.report_id))
                  reportsTelemetry.deleteReport(title, {
                    orgId: orgId!,
                    clusterId: cid!,
                    reportId: rec.report_id!
                  })
                  mutate()
                }}
                title='Are you sure？'
                icon={<QuestionCircleOutlined style={{ color: 'red' }} />}
              >
                <Button className='px-0' type='link' danger>
                  Delete
                </Button>
              </Popconfirm>
            )}
          </Space>
        )
      }
    }
  ]

  useEffect(
    () => () => {
      if (!modalRef.current) {
        return
      }
      modalRef.current.destroy()
    },
    []
  )

  return (
    <Table<ReportReportOverview>
      rowKey='id'
      loading={!error && !listRes}
      columns={columns}
      dataSource={listRes?.data?.reports || []}
      pagination={{
        position: ['bottomRight'],
        total: listRes?.data?.total || 0,
        current: page,
        onChange: (p) => setPage(p)
      }}
    />
  )
}

const useAutoRefresh = (
  query: KeyedMutator<AxiosResponse<ReportListReportResponse, any>>,
  list?: ReportReportOverview[]
) => {
  useEffect(() => {
    let timer: NodeJS.Timeout

    const autoRefresh = () => {
      timer = setTimeout(() => {
        const isPending = list?.some(
          (item) =>
            item.status === StatusType.Running ||
            item.status === StatusType.Pending
        )
        if (!isPending) {
          return
        }

        query()
        autoRefresh()
      }, 5000)
    }

    autoRefresh()

    return () => {
      clearTimeout(timer)
    }
  }, [list, query])
}
