import { SearchOutlined } from '@ant-design/icons'
import {
  Select,
  Table,
  Button,
  Card,
  Modal,
  Divider,
  Descriptions,
  Typography,
  Input,
  Row,
  Col,
  Spin
} from 'antd'
import Item from 'antd/lib/list/Item'
import { ColumnsType } from 'antd/lib/table'
import Title from 'antd/lib/typography/Title'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { set } from 'react-hook-form'

import {
  monitoringControllerListComponentDiffReports,
  monitoringControllerGetComponentDiffReport
} from 'apiClient/services/devops'
import {
  MonitoringComponentDifferenceReportType,
  MonitoringComponentDifferenceReportMetadata,
  MonitoringComponentDifferenceReport,
  MonitoringComponentDifferenceItem,
  MonitoringComponentDifferenceItemsPerCluster
} from 'apiClient/services/devops/interface'

type FlatReportItem = {
  tenant_id: string
  tenant_name: string
  tenant_region: string
  cluster_id: string
  cluster_name: string
  item: MonitoringComponentDifferenceItem
}

export default function ComponentDiff() {
  const [curReportType, setCurReportType] =
    useState<MonitoringComponentDifferenceReportType>(
      MonitoringComponentDifferenceReportType.cluster_spec
    )
  const [curReportMetadata, setCurReportMetadata] =
    useState<MonitoringComponentDifferenceReportMetadata>()
  const [curReportItems, setCurReportItems] = useState<FlatReportItem[]>()
  const [reportMetadatas, setReportMetadatas] = useState<
    MonitoringComponentDifferenceReportMetadata[]
  >([])
  const [filterTenants, setFilterTenants] = useState<string[]>([])
  const [filterTenantRegions, setFilterTenantRegions] = useState<string[]>([])
  const [filterClusters, setFilterClusters] = useState<string[]>([])
  const [filterComponents, setFilterComponents] = useState<string[]>(['pd'])
  const [filterItemKey, setFilterItemKey] = useState<string>('SpuDisplayName')

  useEffect(() => {
    async function fetchReports() {
      try {
        const data = (
          await monitoringControllerListComponentDiffReports(curReportType)
        ).data
        if (data.metadatas) {
          setCurReportMetadata(data.metadatas[data.metadatas.length - 1]) // Set the latest report as default
          setReportMetadatas(data.metadatas)
        }
      } catch (error) {
        Modal.error({
          title: error.response.data.errcode,
          content: error.response.data.errmsg
        })
      }
    }

    fetchReports()
  }, [curReportType])

  useEffect(() => {
    async function fetchCurrentReport() {
      if (!curReportMetadata) {
        return
      }

      try {
        const data = (
          await monitoringControllerGetComponentDiffReport(
            curReportMetadata.type!,
            curReportMetadata.name!
          )
        ).data
        setCurReportItems(flattenReport(data.report!))
      } catch (error) {
        Modal.error({
          title: error.response.data.errcode,
          content: error.response.data.errmsg
        })
      }
    }

    fetchCurrentReport()
  }, [curReportMetadata])

  const column: ColumnsType<FlatReportItem> = [
    {
      title: 'Tenant',
      dataIndex: 'tenant',
      filterMultiple: true,
      filterSearch: true,
      filters: Array.from(
        new Set(
          curReportItems?.map((item) => `${item.tenant_id} ${item.tenant_name}`)
        )
      ).map((tenant_display) => ({
        text: tenant_display,
        value: tenant_display
      })),
      onFilter: (value, record) => true,
      render: (_: any, record) => {
        return (
          <Row>
            <Col span={24}>
              {record.tenant_name ? (
                <Typography.Text
                  style={{ width: 210 }}
                  ellipsis={{ tooltip: record.tenant_name }}
                >
                  {record.tenant_name}
                </Typography.Text>
              ) : (
                <span style={{ color: '#aaa' }}>-</span>
              )}
            </Col>
            <Col span={24}>
              <Typography.Text type="secondary">
                {record.tenant_id}
              </Typography.Text>
            </Col>
          </Row>
        )
      }
    },
    {
      title: 'Tenant Region',
      dataIndex: 'tenant_region',
      filterMultiple: true,
      filters: Array.from(
        new Set(
          curReportItems
            ?.map((item) => item.tenant_region)
            .filter((r) => r !== undefined)
        )
      ).map((region) => ({
        text: region,
        value: region
      })),
      onFilter: () => true,
      render: (_: any, record) => {
        return record.tenant_region
      }
    },
    {
      title: 'Cluster',
      dataIndex: 'cluster',
      filterMultiple: true,
      filterSearch: true,
      filters: Array.from(
        new Set(
          curReportItems
            ?.filter((item) => {
              return (
                filterTenants.length === 0 ||
                filterTenants.includes(item.tenant_id)
              )
            })
            .filter((item) => {
              return (
                filterTenantRegions.length === 0 ||
                filterTenantRegions.includes(item.tenant_region)
              )
            })
            .map((item) => `${item.cluster_id} ${item.cluster_name}`)
        )
      ).map((cluster_display) => ({
        text: cluster_display,
        value: cluster_display
      })),
      onFilter: () => true,
      render: (_: any, record) => {
        return (
          <Row>
            <Col span={24}>
              {record.cluster_name ? (
                <Typography.Text
                  style={{ width: 210 }}
                  ellipsis={{ tooltip: record.cluster_name }}
                >
                  {record.cluster_name}
                </Typography.Text>
              ) : (
                <span style={{ color: '#aaa' }}>-</span>
              )}
            </Col>
            <Col span={24}>
              <Typography.Text type="secondary">
                {record.cluster_id}
              </Typography.Text>
            </Col>
          </Row>
        )
      }
    },
    {
      title: 'Component',
      dataIndex: 'component',
      filterMultiple: true,
      filters: Array.from(
        new Set(
          curReportItems
            ?.map((item) => item.item.component)
            .filter((r) => r !== undefined)
        )
      ).map((region) => ({
        text: region,
        value: region
      })),
      onFilter: () => true,
      filteredValue: filterComponents,
      render: (_: any, record) => {
        return record.item.component
      }
    },
    {
      title: 'Key',
      filterDropdown: ({ clearFilters }) => (
        <div style={{ padding: 8 }}>
          <Input
            placeholder={`Search key`}
            value={filterItemKey}
            onChange={(e) => setFilterItemKey(e.target.value)}
            style={{ marginBottom: 8, display: 'block' }}
          />
          <Button
            onClick={() => clearFilters && setFilterItemKey('')}
            size="small"
            type="link"
          >
            Reset
          </Button>
        </div>
      ),
      filterIcon: (
        <SearchOutlined
          style={{ color: filterItemKey ? '#1677ff' : undefined }}
        />
      ),
      render: (_: any, record) => {
        return record.item.key
      }
    },
    {
      title: 'Default Value',
      render: (_: any, record) => {
        return (
          <span style={{ color: 'green', fontWeight: 'bold' }}>
            {convertToString(record.item.desired)}
          </span>
        )
      }
    },
    {
      title: 'Current Value',
      render: (_: any, record) => {
        return (
          <span style={{ color: 'red', fontWeight: 'bold' }}>
            {convertToString(record.item.actual)}
          </span>
        )
      }
    }
  ]

  return (
    <div>
      <div style={{ display: 'flex', gap: 20, marginBottom: 16 }}>
        <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
          <Typography.Text>Type:</Typography.Text>
          <Select
            defaultValue={curReportType}
            options={Object.values(MonitoringComponentDifferenceReportType).map(
              (i) => ({
                value: i,
                label: i
              })
            )}
            onChange={(value) =>
              setCurReportType(value as MonitoringComponentDifferenceReportType)
            }
            style={{ width: 120 }}
          />
        </div>
        <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
          <Typography.Text>History Reports:</Typography.Text>
          <Select
            value={curReportMetadata?.name}
            options={reportMetadatas.map((md, index) => ({
              value: md.name,
              label:
                index === reportMetadatas.length - 1
                  ? `${md.name} (latest)`
                  : md.name
            }))}
            onChange={(value) => {
              const selectedMetadata = reportMetadatas.find(
                (md) => md.name === value
              )
              setCurReportMetadata(selectedMetadata)
            }}
            style={{ width: 240 }}
          />
        </div>
      </div>

      <Card
        title={<Title level={4}>{`Component Difference Report Detail`}</Title>}
      >
        <Title level={5}>Metadata</Title>
        <Descriptions>
          <Descriptions.Item label="Name">
            {curReportMetadata?.name}
          </Descriptions.Item>
          <Descriptions.Item label="Type">
            {curReportMetadata?.type}
          </Descriptions.Item>
          <Descriptions.Item label="Created At">
            {curReportMetadata?.created_at}
          </Descriptions.Item>
          <Descriptions.Item label="Request Trace ID">
            {curReportMetadata?.request_trace_id}
          </Descriptions.Item>
          <Descriptions.Item label="Total Cluster Count">
            {curReportMetadata?.total_cluster_count}
          </Descriptions.Item>
        </Descriptions>

        <Divider />

        <Title level={5}>Differences</Title>
        {!curReportItems ? (
          <Spin size="large" tip="Loading" />
        ) : (
          <Table<FlatReportItem>
            dataSource={curReportItems
              .filter((item) => {
                return (
                  filterTenants.length === 0 ||
                  filterTenants.includes(item.tenant_id)
                )
              })
              .filter((item) => {
                return (
                  filterTenantRegions.length === 0 ||
                  filterTenantRegions.includes(item.tenant_region)
                )
              })
              .filter((item) => {
                return (
                  filterClusters.length === 0 ||
                  filterClusters.includes(item.cluster_id)
                )
              })
              .filter((item) => {
                return (
                  filterComponents.length === 0 ||
                  filterComponents.includes(item.item.component!)
                )
              })
              .filter((item) => {
                if (filterItemKey === '') {
                  return true
                }
                return item.item.key
                  ?.toLowerCase()
                  .includes(filterItemKey.toLowerCase())
              })
              .sort((a, b) => {
                if (a.tenant_id < b.tenant_id) return -1
                if (a.tenant_id > b.tenant_id) return 1
                return 0
              })}
            columns={column}
            pagination={{ pageSize: 50 }}
            size="small"
            onChange={(_, filters) => {
              setFilterTenants(
                (filters.tenant as string[])?.map((v) => v.split(' ')[0]) || []
              )
              setFilterTenantRegions((filters.tenant_region as string[]) || [])
              setFilterClusters(
                (filters.cluster as string[])?.map((v) => v.split(' ')[0]) || []
              )
              setFilterComponents((filters.component as string[]) || [])
            }}
          />
        )}
      </Card>
    </div>
  )
}

function flattenReport(
  report: MonitoringComponentDifferenceReport
): FlatReportItem[] {
  const differencePerCluster = report.difference ?? []

  return differencePerCluster.flatMap((clusterData) => {
    if (!clusterData.items) {
      return []
    }

    const allItems = Object.values(clusterData.items).flat()

    return allItems.map((item) => ({
      tenant_id: clusterData.tenant_id!,
      tenant_name: clusterData.tenant_name
        ? clusterData.tenant_name
        : 'unknown',
      tenant_region: clusterData.tenant_region
        ? clusterData.tenant_region
        : 'unknown',
      cluster_id: clusterData.cluster_id!,
      cluster_name: clusterData.cluster_name!,
      item: item
    }))
  })
}

function convertToString(input: unknown): string {
  if (input === null) {
    return '-'
  }
  if (
    typeof input === 'string' ||
    typeof input === 'number' ||
    typeof input === 'boolean'
  ) {
    return input.toString()
  } else {
    return JSON.stringify(input)
  }
}
