import { ReloadOutlined } from '@ant-design/icons'
import { color } from '@uiw/react-codemirror'
import {
  Badge,
  Button,
  Card,
  Descriptions,
  Divider,
  notification,
  Space,
  Empty,
  Spin,
  Timeline,
  Tag,
  Typography,
  Layout,
  Menu
} from 'antd'
import type { MenuProps } from 'antd'
import { ColumnsType } from 'antd/lib/table'
import Text from 'antd/lib/typography/Text'
import Title from 'antd/lib/typography/Title'
import { useEffect, useState } from 'react'
import ReactMarkdown from 'react-markdown'
import { useHistory, useLocation, useParams } from 'react-router-dom'

import {
  jiraSummarizeTimelineAsync,
  jiraTriageAsync
} from 'apiClient/services/aiops'
import {
  jiraControllerGetIssueFromJira,
  jiraControllerGetUnifiedIssue
} from 'apiClient/services/devops'
import {
  JiraIssueInJira,
  JiraIssueCustomerEnvironment,
  JiraIssueTriage,
  JiraIssueTimelineSummary
} from 'apiClient/services/devops/interface'
import { ClusterDetailLinkPopover } from 'components/DetailLinkPopover/ClusterDetailLinkPopover'
import { TenantDetailLinkPopover } from 'components/DetailLinkPopover/TenantDetailLinkPopover'
import { toLocal } from 'utils/time'

import GuardianInsight from './GuardianInsight'
import { IssueStatusDisplay } from './utils'

type IssueDetailTabKey = 'overview' | 'triage' | 'timeline_summary' | 'insight'

const ISSUE_DETAIL_MENU_ITEMS: { key: IssueDetailTabKey; label: string }[] = [
  {
    key: 'overview',
    label: 'Overview'
  },
  {
    key: 'triage',
    label: 'Triage'
  },
  {
    key: 'timeline_summary',
    label: 'Timeline Summary'
  },
  {
    key: 'insight',
    label: 'Guardian Insight'
  }
]

const DEFAULT_ISSUE_TAB: IssueDetailTabKey = 'overview'

const getValidTabKey = (maybeKey: string | null): IssueDetailTabKey => {
  if (!maybeKey) {
    return DEFAULT_ISSUE_TAB
  }

  const matched = ISSUE_DETAIL_MENU_ITEMS.find((item) => item.key === maybeKey)
  return matched ? matched.key : DEFAULT_ISSUE_TAB
}

const getActiveKeyFromSearch = (search: string): IssueDetailTabKey =>
  getValidTabKey(new URLSearchParams(search).get('tab'))

export default function IssueDetail() {
  const history = useHistory()
  const location = useLocation()
  const { issue_key } = useParams<{ issue_key: string }>()
  const [issueInJira, setIssueInJira] = useState<JiraIssueInJira>()
  const [loading, setLoading] = useState(true)
  const [reload, setReload] = useState(false)
  const [activeMenuKey, setActiveMenuKey] = useState<IssueDetailTabKey>(() =>
    getActiveKeyFromSearch(location.search)
  )

  useEffect(() => {
    const nextKey = getActiveKeyFromSearch(location.search)
    setActiveMenuKey(nextKey)
  }, [location.search])

  const handleMenuSelect: MenuProps['onClick'] = ({ key }) => {
    const nextKey = key as IssueDetailTabKey
    setActiveMenuKey(nextKey)

    const params = new URLSearchParams(location.search)

    if (nextKey === 'overview') {
      params.delete('tab')
    } else {
      params.set('tab', nextKey)
    }

    const nextSearchString = params.toString()

    history.replace({
      ...location,
      search: nextSearchString ? `?${nextSearchString}` : ''
    })
  }

  async function fetch() {
    setLoading(true)
    setIssueInJira(undefined)

    try {
      const data = (
        await jiraControllerGetIssueFromJira(issue_key, {
          with_comments: false
        })
      ).data.issue
      setIssueInJira(data)
    } catch (error: any) {
      console.error('Failed to fetch issue triage', error)
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    fetch()
  }, [reload])

  const renderOverview = () => {
    return (
      <Card
        title={<Title level={4}>{`Issue Overview`}</Title>}
        extra={
          <Space>
            <Button
              onClick={() => {
                setReload((pre) => !pre)
              }}
              icon={<ReloadOutlined />}
            ></Button>
          </Space>
        }
      >
        <Descriptions column={3}>
          <Descriptions.Item label="Key">
            <Typography.Link
              href={`https://tidb.atlassian.net/browse/${issueInJira?.key}`}
              target="_blank"
            >
              {issueInJira?.key}
            </Typography.Link>
          </Descriptions.Item>
          <Descriptions.Item label="Created At">
            {toLocal(issueInJira?.created_at)}
          </Descriptions.Item>
          <Descriptions.Item label="Updated At">
            {toLocal(issueInJira?.updated_at)}
          </Descriptions.Item>
          <Descriptions.Item label="Status">
            <IssueStatusDisplay status={issueInJira?.status!} />
          </Descriptions.Item>
          <Descriptions.Item label="Priority" span={2}>
            {issueInJira?.priority}
          </Descriptions.Item>
          <Descriptions.Item label="Summary" span={3}>
            {issueInJira?.summary}
          </Descriptions.Item>
        </Descriptions>

        <Divider />
        <Title level={5}>Descrption</Title>
        <Typography.Paragraph style={{ whiteSpace: 'pre-wrap' }}>
          {issueInJira?.description}
        </Typography.Paragraph>

        {issueInJira?.customer_info && (
          <div>
            <Divider />
            <Title level={5}>Customer Information</Title>
            <Descriptions column={1}>
              <Descriptions.Item label="Environment">
                {issueInJira.customer_info.environment}
              </Descriptions.Item>

              {issueInJira.customer_info.environment !==
                JiraIssueCustomerEnvironment.cloud && (
                <Descriptions.Item label="Tenant">
                  {issueInJira.customer_info.tenant_id}
                </Descriptions.Item>
              )}

              {issueInJira.customer_info.environment ===
                JiraIssueCustomerEnvironment.cloud &&
                issueInJira.customer_info.tenant_id && (
                  <Descriptions.Item label="Tenant">
                    <TenantDetailLinkPopover
                      tenantId={issueInJira.customer_info.tenant_id}
                      text={issueInJira.customer_info.tenant_id}
                    />
                  </Descriptions.Item>
                )}

              {issueInJira.customer_info.environment ===
                JiraIssueCustomerEnvironment.cloud &&
                issueInJira.customer_info.cluster_id && (
                  <Descriptions.Item label="Cluster">
                    <ClusterDetailLinkPopover
                      clusterId={issueInJira.customer_info.cluster_id}
                      text={issueInJira.customer_info.cluster_id}
                    />
                  </Descriptions.Item>
                )}
            </Descriptions>
          </div>
        )}
      </Card>
    )
  }

  const contentList: Record<string, React.ReactNode> = {
    overview: renderOverview(),
    triage: <IssueTriageDisplay issue_key={issue_key} />,
    timeline_summary: <IssueTimelineDisplay issue_key={issue_key} />,
    insight: <GuardianInsight />
  }

  if (loading) {
    return (
      <div
        style={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          height: '300px'
        }}
      >
        <Spin tip="Loading..." />
      </div>
    )
  }

  return (
    <Layout style={{ background: 'transparent' }}>
      <Layout.Sider
        theme="light"
        style={{ background: 'transparent', borderRight: '1px solid #f0f0f0' }}
        width={180}
      >
        <Menu
          mode="inline"
          selectedKeys={[activeMenuKey]}
          onClick={handleMenuSelect}
          style={{ height: '100%', borderRight: 0 }}
          items={ISSUE_DETAIL_MENU_ITEMS}
        />
      </Layout.Sider>
      <Layout.Content style={{ padding: '0 24px', minHeight: 280 }}>
        {contentList[activeMenuKey] ?? contentList.overview}
      </Layout.Content>
    </Layout>
  )
}

function IssueTriageDisplay({ issue_key }: { issue_key: string }) {
  const [issueTriage, setIssueTriage] = useState<JiraIssueTriage>()
  const [loading, setLoading] = useState(true)
  const [notFound, setNotFound] = useState(false)
  const [reload, setReload] = useState(false)

  async function fetch() {
    setLoading(true)
    setNotFound(false)
    setIssueTriage(undefined)

    try {
      const data = (
        await jiraControllerGetUnifiedIssue(issue_key, {
          with_triage: true
        })
      ).data

      if (data.issue?.issue_triage === undefined) {
        setNotFound(true)
        setIssueTriage(undefined)
      } else {
        setNotFound(false)
        setIssueTriage(data.issue?.issue_triage)
      }
    } catch (error: any) {
      notification.error({
        message: 'Failed',
        description: 'Failed to fetch issue triage'
      })
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    fetch()
  }, [reload])

  const handleTriage = async () => {
    try {
      const data = (await jiraTriageAsync(issue_key)).data
      notification.success({
        message: 'Triage Triggered',
        duration: null,
        description: `Successfully triggered issue triage. It may take a few minutes to complete. Operation ID: ${data.id}`
      })
      setReload((pre) => !pre)
    } catch (error: any) {
      notification.error({
        message: 'Failed',
        description: 'Failed to trigger issue triage'
      })
    }
  }

  const renderContent = () => {
    if (loading) {
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            height: '300px'
          }}
        >
          <Spin tip="Loading..." />
        </div>
      )
    }

    if (notFound) {
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            height: '300px'
          }}
        >
          <Empty description="This issue have not been triaged." />
        </div>
      )
    }

    return (
      <div>
        <Descriptions>
          <Descriptions.Item label="Key">{issueTriage?.key}</Descriptions.Item>
          <Descriptions.Item label="Triaged At">
            {toLocal(issueTriage?.created_at)}
          </Descriptions.Item>
        </Descriptions>

        <Divider />
        <Title level={5}>Tags</Title>
        <Descriptions>
          <Descriptions.Item label="Scene" span={3}>
            {issueTriage?.tags?.scene && <Tag>{issueTriage?.tags?.scene}</Tag>}
          </Descriptions.Item>
          <Descriptions.Item label="Root Cause" span={3}>
            {issueTriage?.tags?.root_cause && (
              <Tag>{issueTriage?.tags?.root_cause}</Tag>
            )}
          </Descriptions.Item>
          <Descriptions.Item label="Solution" span={3}>
            {issueTriage?.tags?.solution && (
              <Tag>{issueTriage?.tags?.solution}</Tag>
            )}
          </Descriptions.Item>
          <Descriptions.Item label="Preventability" span={3}>
            {issueTriage?.tags?.preventability && (
              <Tag>{issueTriage?.tags?.preventability}</Tag>
            )}
          </Descriptions.Item>
        </Descriptions>

        <Divider />
        <Title level={5}>Brief Summary</Title>
        <ReactMarkdown>{issueTriage?.brief_summary ?? ''}</ReactMarkdown>
      </div>
    )
  }

  return (
    <div>
      <Card
        title={<Title level={4}>{`Issue Triage`}</Title>}
        extra={
          <Space>
            <Button type="primary" onClick={handleTriage}>
              Triage
            </Button>
            <Button
              onClick={() => {
                setReload((pre) => !pre)
              }}
              icon={<ReloadOutlined />}
            ></Button>
          </Space>
        }
      >
        {renderContent()}
      </Card>
    </div>
  )
}

function IssueTimelineDisplay({ issue_key }: { issue_key: string }) {
  const [issueTimeline, setIssueTimeline] = useState<JiraIssueTimelineSummary>()
  const [loading, setLoading] = useState(true)
  const [notFound, setNotFound] = useState(false)
  const [reload, setReload] = useState(false)

  async function fetch() {
    setLoading(true)
    setNotFound(false)
    setIssueTimeline(undefined)

    try {
      const data = (await jiraControllerGetUnifiedIssue(issue_key)).data
      if (data.issue?.issue_timeline_summary === undefined) {
        setNotFound(true)
        setIssueTimeline(undefined)
      } else {
        setNotFound(false)
        setIssueTimeline(data.issue?.issue_timeline_summary)
      }
    } catch (error: any) {
      notification.error({
        message: 'Failed',
        description: 'Failed to fetch issue timeline summary',
        placement: 'topRight'
      })
    } finally {
      setLoading(false)
    }
  }

  const handleGenerate = async () => {
    try {
      const data = (await jiraSummarizeTimelineAsync(issue_key, {})).data
      notification.success({
        message: 'Summary Generation Triggered',
        duration: null,
        description: `Successfully triggered timeline summary generation. It may take a few minutes to complete. Operation ID: ${data.id}`
      })
      setReload((pre) => !pre)
    } catch (error: any) {
      notification.error({
        message: 'Failed',
        description: 'Failed to trigger timeline summary generation',
        placement: 'topRight'
      })
    }
  }

  useEffect(() => {
    fetch()
  }, [reload])

  const renderContent = () => {
    if (loading) {
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            height: '300px'
          }}
        >
          <Spin tip="Loading..." />
        </div>
      )
    }

    if (notFound) {
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            height: '300px'
          }}
        >
          <Empty description="Timeline summary have not been generated." />
        </div>
      )
    }

    return (
      <div>
        <Timeline mode="left">
          {issueTimeline?.timelines?.map((item) => (
            <Timeline.Item>
              <div>
                <b>{toLocal(Number(item.begin_time) / 1000)}</b>
                <br></br>
                <Text>{item.description}</Text>
              </div>
            </Timeline.Item>
          ))}
        </Timeline>
      </div>
    )
  }

  return (
    <div>
      <Card
        title={<Title level={4}>{`Issue Timeline Summary`}</Title>}
        extra={
          <Space>
            <Button type="primary" onClick={handleGenerate}>
              Generate
            </Button>
            <Button
              onClick={() => {
                setReload((pre) => !pre)
              }}
              icon={<ReloadOutlined />}
            ></Button>
          </Space>
        }
      >
        {renderContent()}
      </Card>
    </div>
  )
}
