import React, { useMemo } from 'react'

import { GlobalOutlined } from '@ant-design/icons'
import { Descriptions } from 'antd'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'

import { ComputeEngineHealthMetricAdvice } from '@clinic/client'
import EmptyResult from '~/components/EmptyResult'
import { ClinicIcon } from '~/components/Icons'
import LoadingSpin from '~/components/LoadingSpin'
import LanguageDropdown from '~/componentv2/LanguageDropdown'
import { navbarTelemetry, healthReportTelemetry } from '~/telemetry'
import { RemoteNamespace } from '~/translations'
import { formatDateTime } from '~/utils/date-time'

import {
  type HealthReportResponseContent,
  useGetReportContent
} from './helpers'
import { HEALTH_REPORT_NS } from './translations'

type MetricAdvice = ComputeEngineHealthMetricAdvice & {
  sourceType: RemoteNamespace
}

interface AdviceListProps {
  data: MetricAdvice[]
}

const OTHERS_CATEGORY_KEY = 'others'

const AdviceList: React.FC<AdviceListProps> = ({ data }) => {
  const { t } = useTranslation([RemoteNamespace.Metrics, RemoteNamespace.Log])
  const metricsMap = data.reduce(
    (prev, cur) => {
      // combine the other category and log advices with unknown category
      if (
        !cur.category?.[0] ||
        cur.category[0] === 'other' ||
        cur.sourceType === RemoteNamespace.Log
      ) {
        prev[OTHERS_CATEGORY_KEY].push(cur)
        return prev
      }

      if (prev[cur.category![0]]) {
        prev[cur.category![0]].push(cur)
      } else {
        prev[cur.category![0]] = [cur]
      }
      return prev
    },
    { [OTHERS_CATEGORY_KEY]: [] } as { [k: string]: MetricAdvice[] }
  )

  return (
    <>
      {Object.keys(metricsMap)
        .sort((a, b) => {
          if (a === OTHERS_CATEGORY_KEY) {
            return 1
          }
          if (b === OTHERS_CATEGORY_KEY) {
            return -1
          }
          return 0
        })
        .map(
          (category) =>
            !!metricsMap[category].length && (
              <React.Fragment key={category}>
                <h3>{category}</h3>
                {metricsMap[category].map((advice) => {
                  return (
                    <Descriptions
                      key={advice.id}
                      className='mb-6'
                      bordered
                      size='small'
                      column={1}
                      labelStyle={{ width: '160px' }}
                      title={<span className='font-light'>{advice.name}</span>}
                    >
                      <Descriptions.Item label='Component'>
                        {advice.component || '-'}
                      </Descriptions.Item>
                      <Descriptions.Item label='Source'>
                        {advice.sourceType}
                      </Descriptions.Item>
                      {advice.instance && (
                        <Descriptions.Item label='Instance'>
                          {advice.instance}
                        </Descriptions.Item>
                      )}
                      {advice.sourceType === RemoteNamespace.Metrics && (
                        <Descriptions.Item label='Fact'>
                          {t(`${advice.content?.key}.fact`, {
                            ns: advice.sourceType,
                            ...(advice?.content?.variables || {})
                          })}
                        </Descriptions.Item>
                      )}
                      <Descriptions.Item label='Suggestion'>
                        {t(
                          advice.sourceType === RemoteNamespace.Metrics
                            ? `${advice.content?.key}.suggestion`
                            : advice.content?.key!,
                          {
                            ns: advice.sourceType,
                            ...(advice?.content?.variables || {})
                          }
                        )}
                      </Descriptions.Item>
                      {advice.kb && (
                        <Descriptions.Item label='KB'>
                          {advice.kb}
                        </Descriptions.Item>
                      )}
                    </Descriptions>
                  )
                })}
              </React.Fragment>
            )
        )}
    </>
  )
}

interface HealthReportContentProps {
  data: HealthReportResponseContent
}

const HealthReportContent: React.FC<HealthReportContentProps> = ({ data }) => {
  const {
    data: result = {},
    args: { start_ts: startTime = 0, stop_ts: endTime = 0 } = {}
  } = data

  const advices = useMemo<MetricAdvice[]>(() => {
    return [
      ...(result?.metric?.advice || []).map(
        (advice) =>
          ({
            ...advice,
            sourceType: RemoteNamespace.Metrics
          } as MetricAdvice)
      ),
      ...(result?.log?.advice || []).map(
        (advice) =>
          ({
            ...advice,
            sourceType: RemoteNamespace.Log
          } as MetricAdvice)
      )
    ]
  }, [result])

  const { t } = useTranslation(HEALTH_REPORT_NS)

  return (
    <div className='h-full flex flex-col overflow-auto'>
      <header className='flex-none flex bg-white shadow-sm'>
        <div className='flex justify-between items-center h-12 px-8 m-auto w-full max-w-[1440px] bg-white'>
          <Link to='/' onClick={() => navbarTelemetry.clickLogo()}>
            <ClinicIcon />
          </Link>
          <LanguageDropdown
            onClick={(lang) => healthReportTelemetry.changeReportLang(lang)}
          >
            <a className='text-gray-400'>
              <GlobalOutlined /> {t('lang')}
            </a>
          </LanguageDropdown>
        </div>
      </header>
      <main className='flex-auto m-auto w-full max-w-[1440px] h-full py-6'>
        <article className='px-8 py-8 mx-8 min-h-full bg-white'>
          <header className='mb-8'>
            <h1 className='text-4xl font-semibold'>{t('title')}</h1>
          </header>
          <section className='mb-8'>
            <h2 className='mb-6'>{t('section.basic')}</h2>
            <section className='mb-6'>
              <h3 className='font-normal mb-5'>{t('basic.timeRange')}</h3>
              <Descriptions
                layout='vertical'
                bordered
                size='small'
                className='w-[500px]'
              >
                <Descriptions.Item label='Start Time'>
                  {formatDateTime(startTime)}
                </Descriptions.Item>
                <Descriptions.Item label='End Time'>
                  {formatDateTime(endTime)}
                </Descriptions.Item>
              </Descriptions>
            </section>
          </section>
          <section className='mb-8'>
            <h2 className='mb-6'>{t('section.issue')}</h2>
            <AdviceList data={advices} />
          </section>
          <section className='mb-8'>
            <h2 className='mb-6'>{t('section.detail')}</h2>
            <Descriptions
              bordered
              size='small'
              column={1}
              labelStyle={{ width: '160px' }}
            >
              <Descriptions.Item label='Rule executed'>
                {result?.metric?.stats?.checkedRules ?? '-'}
              </Descriptions.Item>
              <Descriptions.Item label='Metrics scanned'>
                {result?.metric?.stats?.scannedMetrics ?? '-'}
              </Descriptions.Item>
              <Descriptions.Item label='Log scanned'>
                {result?.log?.stats?.scannedLogs ?? '-'}
              </Descriptions.Item>
            </Descriptions>
          </section>
        </article>
      </main>
    </div>
  )
}

interface HealthReportProps {
  orgId: string
  clusterId: string
  reportId: string
}

const HealthReport: React.FC<HealthReportProps> = ({
  orgId,
  clusterId,
  reportId
}) => {
  const { data, isLoading, error } = useGetReportContent({
    orgId,
    clusterId,
    reportId
  })

  if (isLoading) {
    return <LoadingSpin />
  }

  if (error) {
    return (
      <EmptyResult
        className='mt-24'
        title='Something went wrong'
        subTitle='Please retry later'
      />
    )
  }

  return <HealthReportContent data={data} />
}

export default HealthReport
