import { ReloadOutlined, InfoCircleOutlined } from '@ant-design/icons'
import {
  Button,
  Descriptions,
  Modal,
  Card,
  Tooltip,
  Divider,
  Space,
  Form,
  Select,
  Alert
} from 'antd'
import TextArea from 'antd/es/input/TextArea'
import Table, { ColumnsType } from 'antd/lib/table'
import Title from 'antd/lib/typography/Title'
import { Base64 } from 'js-base64'
import { useCallback, useEffect, useState } from 'react'
import { Link, useParams } from 'react-router-dom'

import {
  releaseControllerCancelChange,
  releaseControllerExecuteDeployment,
  releaseControllerGetChange,
  releaseControllerIsDeploymentReady,
  releaseControllerSubmitChange,
  releaseControllerVerifyDeployment,
  releaseControllerCloseChange,
  operationControllerListInstances
} from 'apiClient/services/devops'
import {
  AuditAuditLogType,
  ReleaseChangeDeployment,
  ReleaseGetChangeResp,
  ReleaseReleaseTicket,
  ReleaseCloseChangeReq,
  ReleaseChangeStatus,
  ReleaseChangeResult,
  ReleaseChangeDeployEEAPI
} from 'apiClient/services/devops/interface'
import ApprovalTable from 'components/ApprovalTable'
import AuditTable from 'components/Audit'
import ModalForm from 'components/ModalForm'
import { toLocal } from 'pages/Devops/Maintenance/Detail'

import { TICKET_URL } from '../helper'

import EEAPIDetail from './EEAPIDetail'
import FillValidationForm, { ValidationForm } from './Forms/FillValidationForm'

export const GithubLocationToLink = (val: string) => {
  const regex = /^(\w+)\/([\w-]+)#(\d+)$/
  const match = val.match(regex)
  if (match) {
    const location = match[0]
    const owner = match[1]
    const repo = match[2]
    const number = match[3]
    return 'https://github.com/' + owner + '/' + repo + '/pull/' + number
  } else {
    return undefined
  }
}

export const LinkToGithubLocation = (link: string) => {
  const regex = /https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/pull\/(\d+)/
  const match = link.match(regex)
  if (match) {
    const owner = match[1]
    const repo = match[2]
    const prNumber = match[3]
    return `${owner}/${repo}#${prNumber}`
  } else {
    return 'Invalid URL'
  }
}

export const ChangeDetailPage = () => {
  const { change_id, release_id } = useParams<{
    change_id: string
    release_id: string
  }>()

  const [reload, setReload] = useState(false)

  const [changeInfo, setChangeInfo] = useState<ReleaseGetChangeResp>()

  const [verifyForm, setVerifyForm] = useState(false)
  const [verifyOrder, setVerifyOrder] = useState<number>()

  const [closeWindowOpen, setCloseWindowOpen] = useState(false)

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

  async function fetch() {
    try {
      const data = (
        await releaseControllerGetChange(parseInt(change_id), {
          with_detail: true,
          with_change_items: true,
          with_release: true,
          with_applicant: true,
          with_application: true,
          with_tickets: true
        })
      ).data
      setChangeInfo(data)
    } catch (e) {
      console.error(e)
    }
  }

  const handleDeploy = (order: number) => {
    return async () => {
      const force = await releaseControllerIsDeploymentReady(
        parseInt(change_id),
        order
      )
      let window_inf
      let forceDeploy: boolean
      if (force.data.is_ready) {
        window_inf = 'sure to execute this Deployment?'
        forceDeploy = false
      } else {
        window_inf =
          'This deployment is not ready. Are you sure to deploy by force?\n' +
          'Reasons: ' +
          force.data.reasons?.join('; ')
        forceDeploy = true
      }
      Modal.info({
        title: 'Info',
        closable: true,
        content: (
          <div>
            <p>{window_inf}</p>
          </div>
        ),
        okText: 'Confirm',
        async onOk() {
          try {
            await releaseControllerExecuteDeployment(
              parseInt(change_id),
              order,
              { force: forceDeploy }
            )
            Modal.success({
              title: 'info',
              content: (
                <div>
                  <p>Successfully Deploy</p>
                </div>
              ),
              onOk() {}
            })
            setReload((pre) => !pre)
          } catch (error) {
            Modal.error({
              title: error.response.data.errcode,
              content: error.response.data.errmsg
            })
            setReload((pre) => !pre)
          }
        }
      })
    }
  }

  const disableDeploy = (record: ReleaseChangeDeployment) => {
    if (record.order !== undefined && changeInfo?.change?.deployments) {
      return record.order === 0
        ? changeInfo?.change?.status !== 'wait_for_deploy'
        : changeInfo?.change?.deployments[record.order - 1].deployed_at ===
            undefined ||
            changeInfo.change.deployments[record.order].deployed_at !==
              undefined
    } else {
      return true
    }
  }

  const handleClickVerify = (order: number | undefined) => {
    return () => {
      setVerifyOrder(order)
      setVerifyForm(true)
    }
  }

  const disableValidate = (record: ReleaseChangeDeployment) => {
    return record.status !== 'deployed'
  }

  const renderFormFields = useCallback(() => {
    return <FillValidationForm />
  }, [verifyForm])

  const handleValidate = async (payload: ValidationForm) => {
    try {
      if (verifyOrder != undefined) {
        await releaseControllerVerifyDeployment(
          parseInt(change_id),
          verifyOrder,
          {
            note: payload.description
          }
        )
        Modal.success({
          title: 'info',
          content: (
            <div>
              <p>Successfully Validate</p>
            </div>
          ),
          onOk() {}
        })
        setVerifyForm(false)
        setReload((pre) => !pre)
      }
    } catch (error) {
      Modal.error({
        title: error.response.data.errcode,
        content: error.response.data.errmsg
      })
      setReload((pre) => !pre)
    }
  }

  const handleCancelVerify = useCallback(() => {
    setVerifyForm(false)
  }, [])

  const handleCancelChange = async () => {
    Modal.info({
      title: 'Info',
      closable: true,
      content: (
        <div>
          <p>Do you want to CANCEL this change?</p>
        </div>
      ),
      okText: 'Confirm',
      async onOk() {
        try {
          await releaseControllerCancelChange(parseInt(change_id))
          Modal.success({
            title: 'Info',
            content: (
              <div>
                <p>Successfully Cancel</p>
              </div>
            ),
            onOk() {}
          })
          setReload((pre) => !pre)
        } catch (error) {
          Modal.error({
            title: error.response.data.errcode,
            content: error.response.data.errmsg
          })
        }
      }
    })
  }

  const handleSubmit = async () => {
    Modal.info({
      title: 'Info',
      closable: true,
      content: (
        <div>
          <p>Do you want to Submit this Draft?</p>
        </div>
      ),
      okText: 'Confirm',
      async onOk() {
        try {
          await releaseControllerSubmitChange(parseInt(change_id))
          Modal.success({
            title: 'Info',
            content: (
              <div>
                <p>Successfully Submit the Draft</p>
              </div>
            ),
            onOk() {}
          })
          setReload((pre) => !pre)
        } catch (error) {
          Modal.error({
            title: error.response.data.errcode,
            content: error.response.data.errmsg
          })
        }
      }
    })
  }

  const canCancel = () => {
    if (changeInfo?.change?.status) {
      return (
        changeInfo?.change?.status !== 'in_progress' &&
        changeInfo?.change?.status !== 'closed' &&
        changeInfo?.change?.status !== 'observing'
      )
    } else {
      return false
    }
  }

  const canUpdate = () => {
    if (changeInfo?.change?.status) {
      return (
        changeInfo.change?.status === ReleaseChangeStatus.created ||
        changeInfo.change?.status === ReleaseChangeStatus.approving ||
        changeInfo.change?.status === ReleaseChangeStatus.withdrawn ||
        changeInfo.change?.status === ReleaseChangeStatus.wait_for_deploy ||
        changeInfo.change?.status === ReleaseChangeStatus.draft
      )
    } else {
      return false
    }
  }

  const canClose = () => {
    if (changeInfo?.change?.status) {
      return (
        changeInfo.change?.status === ReleaseChangeStatus.in_progress ||
        changeInfo.change?.status === ReleaseChangeStatus.observing
      )
    } else {
      return false
    }
  }

  const CloseModalFormFields = () => {
    return (
      <>
        <Form.Item name="result" label="Result">
          <Select
            options={[
              {
                value: ReleaseChangeResult.successful,
                label: 'Successful'
              },
              {
                value: ReleaseChangeResult.failed,
                label: 'Failed'
              },
              {
                value: ReleaseChangeResult.failed_partially,
                label: 'Failed Partially'
              },
              {
                value: ReleaseChangeResult.rollback,
                label: 'Rollback'
              }
            ]}
          />
        </Form.Item>
        <Form.Item name="summary" label="Summary" required={true}>
          <TextArea rows={4} />
        </Form.Item>
      </>
    )
  }

  const handleClose = async (payload: ReleaseCloseChangeReq) => {
    try {
      await releaseControllerCloseChange(parseInt(change_id), payload).then(
        () => {
          setCloseWindowOpen(false)
          setReload((pre) => !pre)
        }
      )
    } catch (error) {
      Modal.error({
        title: error.response.data.errcode,
        content: error.response.data.errmsg
      })
    }
  }

  const columnsDM: ColumnsType<ReleaseReleaseTicket> = [
    {
      title: 'Name',
      render: (_: any, record) => {
        return (
          <div>
            <p>
              <a
                href={TICKET_URL() + record.name}
                target="_blank"
                rel="noreferrer"
              >
                {record.name}
              </a>
            </p>
          </div>
        )
      }
    },
    {
      title: 'Status',
      render: (_: any, record) => {
        return record.status
      }
    },
    {
      title: 'Summary',
      render: (_: any, record) => {
        return record.summary
      }
    },
    {
      title: 'Related PRs',
      render: (_: any, record) => {
        return record.github_pr_locations?.map((val) => {
          return (
            <p style={{ marginBottom: 1 }}>
              <a
                href={GithubLocationToLink(val)}
                target="_blank"
                rel="noreferrer"
              >
                {val}
              </a>
            </p>
          )
        })
      }
    },
    {
      title: 'Action',
      render: (_: any, record) => {
        return (
          <div>
            <Link to={`/release/${release_id}/tickets/${record.name}`}>
              Detail
            </Link>
          </div>
        )
      }
    }
  ]

  const columsDeployment: ColumnsType<ReleaseChangeDeployment> = [
    {
      title: 'Order',
      render: (_: any, record) => {
        return record.order
      }
    },
    {
      title: 'Method',
      render: (_: any, record) => {
        return record.method
      }
    },
    {
      title: 'Description',
      render: (_: any, record) => {
        return record.info?.description
      }
    },
    {
      title: 'Detail',
      render: (_: any, record) => {
        if (record.method === 'argocd') {
          return record.info?.argocd?.deploy_prs ? (
            <a
              href={record.info?.argocd?.deploy_prs[0].link}
              target="_blank"
              rel="noreferrer"
            >
              {LinkToGithubLocation(
                record.info?.argocd?.deploy_prs[0].link || ''
              )}
            </a>
          ) : (
            ''
          )
        } else if (record.method === 'ee_api') {
          return record.info?.ee_api ? (
            <EEAPIDetail
              info={record.info.ee_api}
              release_id={release_id}
              change_id={change_id}
            />
          ) : null
        }
        return ''
      }
    },
    {
      title: 'Regions',
      render: (_: any, record) => {
        return <div>{record.regions?.join(',\n')}</div>
      }
    },
    {
      title: 'Deployed At',
      render: (_: any, record) => {
        return record.deployed_at
          ? new Date(record.deployed_at).toLocaleString(undefined, {
              hour12: false
            })
          : null
      }
    },
    {
      title: 'Actions',
      render: (_: any, record) => {
        return (
          <div>
            <Button
              type="link"
              disabled={disableDeploy(record)}
              onClick={handleDeploy(
                record.order !== undefined ? record.order : -1
              )}
            >
              Deploy
            </Button>
            <Button
              type="link"
              onClick={handleClickVerify(record.order)}
              disabled={disableValidate(record)}
            >
              Validate
            </Button>
          </div>
        )
      }
    }
  ]

  const [activeTabKey, setActiveTabKey] = useState<string>('approval')
  const onTabChange = (key: string) => {
    setActiveTabKey(key)
  }

  const tabList = [
    {
      key: 'approval',
      tab: 'Approval'
    },
    {
      key: 'audit',
      tab: 'Audit Logs'
    }
  ]

  const contentList: Record<string, React.ReactNode> = {
    audit: changeInfo?.change ? (
      <AuditTable type={AuditAuditLogType.change} id={changeInfo?.change.id} />
    ) : (
      <div>Loading...</div>
    ),
    approval: changeInfo?.change?.approval_id ? (
      <ApprovalTable id={changeInfo?.change?.approval_id}></ApprovalTable>
    ) : (
      <div>Loading...</div>
    )
  }

  return (
    <div>
      <Card
        title={<Title level={4}>{`Release Change Detail`}</Title>}
        extra={
          <Space>
            {changeInfo?.change?.status === ReleaseChangeStatus.draft && (
              <Button
                type="primary"
                disabled={changeInfo?.change?.status !== 'draft'}
                onClick={handleSubmit}
              >
                Submit
              </Button>
            )}

            {canUpdate() && (
              <Button type="primary" disabled={!canUpdate()}>
                <Link to={`/release/${release_id}/${change_id}/update`}>
                  Update
                </Link>
              </Button>
            )}

            {canCancel() && (
              <Button
                type="primary"
                onClick={handleCancelChange}
                disabled={!canCancel()}
              >
                Cancel
              </Button>
            )}

            {canClose() && (
              <Button
                type="primary"
                onClick={() => {
                  setCloseWindowOpen(true)
                }}
              >
                Close
              </Button>
            )}

            <Button
              type="default"
              icon={<ReloadOutlined />}
              onClick={() => {
                setReload((pre) => !pre)
              }}
            ></Button>
          </Space>
        }
      >
        <Title level={5}>Basic Information</Title>
        <Descriptions>
          <Descriptions.Item label="Change Name">
            {changeInfo?.change?.name}
          </Descriptions.Item>
          <Descriptions.Item label="Release Name">
            {changeInfo?.change?.release?.name}
          </Descriptions.Item>
          <Descriptions.Item label="Applicant">
            {changeInfo?.change?.applicant_email}
          </Descriptions.Item>
          <Descriptions.Item label="Application">
            {changeInfo?.change?.application?.name}
          </Descriptions.Item>
          <Descriptions.Item label="Status">
            {changeInfo?.change?.status}
          </Descriptions.Item>
          <Descriptions.Item label="Type">
            {changeInfo?.change?.type}
          </Descriptions.Item>
          <Descriptions.Item label="Change Window(Local Time)" span={2}>
            from {toLocal(changeInfo?.change?.window_start_at)} <br />
            to {toLocal(changeInfo?.change?.window_end_at)}
          </Descriptions.Item>
          <br />
          <Descriptions.Item label="Risk Level">
            {changeInfo?.change?.risk_level}
          </Descriptions.Item>
          <Descriptions.Item label="Tier">
            {changeInfo?.change?.tier?.join(', ')}
          </Descriptions.Item>
          <Descriptions.Item label="Outage" span={2}>
            {changeInfo?.change?.detail?.need_outage ? <>Yes</> : <>No</>}
          </Descriptions.Item>
          <Descriptions.Item label="Staging Test Report" span={3}>
            {changeInfo?.change?.detail?.staging_test_report}
          </Descriptions.Item>
          <Descriptions.Item label="Rollback Plan" span={3}>
            {changeInfo?.change?.detail?.rollback_plan}
          </Descriptions.Item>
          <Descriptions.Item label="Release Note" span={3}>
            {changeInfo?.change?.detail?.note}
          </Descriptions.Item>
        </Descriptions>

        {changeInfo?.change?.status_reason !== '' ? (
          <Alert
            message="NOTE"
            description={changeInfo?.change?.status_reason}
            type="info"
            showIcon
          />
        ) : (
          <></>
        )}

        <Divider />
        <Title level={5}>Selected DM Tickets</Title>
        <Table<ReleaseReleaseTicket>
          columns={columnsDM}
          rowKey="id"
          dataSource={changeInfo?.change?.change_items}
          size="small"
          pagination={false}
        ></Table>

        <Divider />
        <Title level={5}>Deployments</Title>
        <Table<ReleaseChangeDeployment>
          columns={columsDeployment}
          rowKey="id"
          dataSource={changeInfo?.change?.deployments}
          size="small"
          pagination={false}
        ></Table>
      </Card>

      <Card
        tabList={tabList}
        tabProps={{ size: 'middle' }}
        bordered={false}
        activeTabKey={activeTabKey}
        onTabChange={(key) => {
          onTabChange(key)
        }}
      >
        {contentList[activeTabKey]}
      </Card>

      <ModalForm<ValidationForm>
        visible={!!verifyForm}
        name="user"
        title={'Validate Deploy'}
        getFields={renderFormFields}
        onSubmit={handleValidate}
        onCancel={handleCancelVerify}
      />

      <ModalForm<ReleaseCloseChangeReq>
        visible={!!closeWindowOpen}
        name="Close Change"
        title={'Close Change'}
        getFields={() => {
          return <CloseModalFormFields />
        }}
        okText={'Confirm'}
        onSubmit={handleClose}
        onCancel={() => {
          setCloseWindowOpen(false)
        }}
      />
    </div>
  )
}

export default ChangeDetailPage
