import {
  Button,
  Card,
  Checkbox,
  Form,
  FormInstance,
  List,
  Modal,
  Input,
  Result,
  Typography
} from 'antd'
import form from 'antd/lib/form'
import clsx from 'clsx'
import { useCallback, useContext, useEffect, useState } from 'react'
import useProfileContext from 'useProfileContext'

import {
  remediationTicketControllerApproveTicketPhase,
  remediationTicketControllerCancelTicket,
  remediationTicketControllerRejectTicketPhase,
  remediationTicketControllerSubmitTicketPhase
} from 'apiClient/services/devops'
import {
  EntityRemediationApprovalFlow,
  EntityRemediationApprovalFlowNodeAction,
  EntityRemediationTicket,
  EntityRemediationTicketPhase,
  EntityRemediationTicketPhaseApproval,
  EntityRemediationTicketStatus,
  RemediationticketSubmitTicketPhaseReq
} from 'apiClient/services/devops/interface'

import { RemediationPageContext } from './PageContext'
import { getPhaseByName, PhaseInstance } from './phases'
import { defaultApprovalInfo, findTicketApprovalByID } from './utils'

const RemediationTicketInteractPanel = function ({
  ticket,
  ticketApprovals,
  approvalFlow,
  incidentDescription,
  incidentPostmortemLink
}: {
  ticket: EntityRemediationTicket
  ticketApprovals?: EntityRemediationTicketPhaseApproval[]
  approvalFlow?: EntityRemediationApprovalFlow
  incidentDescription?: string
  incidentPostmortemLink?: string
}) {
  const {
    profile: { userEmail }
  } = useProfileContext()

  const phaseInstance = getPhaseByName(ticket.phase!)
  const approvalRequestTitle = (
    <span className="remediation-approval-request-title">
      <span className="remediation-approval-request-badge">Pending</span>
      Approval Request
    </span>
  )
  const informationNeededTitle = (
    <span className="remediation-info-needed-title">
      <span className="remediation-info-needed-badge">Required</span>
      {phaseInstance?.label}: Information Needed
    </span>
  )
  const finalStatusTitle =
    ticket.phase === EntityRemediationTicketPhase.closed ? (
      <span className="remediation-final-status-title">
        <span className="remediation-final-status-badge remediation-final-status-badge-closed">
          Closed
        </span>
        Ticket Closed
      </span>
    ) : ticket.phase === EntityRemediationTicketPhase.succeed ? (
      <span className="remediation-final-status-title">
        <span className="remediation-final-status-badge remediation-final-status-badge-success">
          Done
        </span>
        Ticket Approved
      </span>
    ) : null
  if (!phaseInstance) {
    console.log(
      'invalid phase Instance in RemediationTicketInteractPanel()',
      phaseInstance
    )
    return <></>
  }

  if (!userEmail) {
    return <></>
  }

  if (
    ticket.current_responsible_person_email !== userEmail ||
    phaseInstance.isfinal
  ) {
    return (
      <Card
        className={clsx(
          'remediation-unified-card remediation-interactive-card',
          phaseInstance.isfinal
            ? ticket.phase === EntityRemediationTicketPhase.closed
              ? 'remediation-final-card remediation-final-card-closed'
              : 'remediation-final-card remediation-final-card-success'
            : 'remediation-info-needed-card'
        )}
        title={
          phaseInstance.isfinal ? finalStatusTitle : informationNeededTitle
        }
      >
        <RemediationViewerPanel
          ticket={ticket}
          currUserEmail={userEmail}
          ticketApprovals={ticketApprovals}
        />
      </Card>
    )
  }

  if (
    ticket.status === EntityRemediationTicketStatus.pending ||
    ticket.status === EntityRemediationTicketStatus.rejected
  ) {
    return (
      <Card
        className="remediation-unified-card remediation-interactive-card remediation-info-needed-card"
        title={informationNeededTitle}
      >
        <RemediationSubmitForm
          ticket={ticket}
          phaseInstance={phaseInstance}
          incidentDescription={incidentDescription}
          incidentPostmortemLink={incidentPostmortemLink}
        />
      </Card>
    )
  } else if (ticket.status === EntityRemediationTicketStatus.approving) {
    const currentTicketApproval =
      ticketApprovals &&
      ticket.appr_id &&
      findTicketApprovalByID(ticketApprovals, ticket.appr_id)

    const toPhase =
      currentTicketApproval && getPhaseByName(currentTicketApproval.to_phase)

    if (!!toPhase)
      return (
        <Card
          className="remediation-unified-card remediation-interactive-card remediation-approval-request-card"
          title={approvalRequestTitle}
        >
          <RemediationApprovalDiag
            key={`${ticket.id}-${ticket.appr_id || 0}-${toPhase.name}`}
            ticket={ticket}
            fromPhase={phaseInstance}
            toPhase={toPhase}
            approvalFlow={approvalFlow}
            incidentDescription={incidentDescription}
            incidentPostmortemLink={incidentPostmortemLink}
          />
        </Card>
      )
  }

  return <></>
}

const RemediationApprovalDiag = function ({
  ticket,
  fromPhase,
  toPhase,
  approvalFlow,
  incidentDescription,
  incidentPostmortemLink
}: {
  ticket: EntityRemediationTicket
  fromPhase: PhaseInstance
  toPhase: PhaseInstance
  approvalFlow?: EntityRemediationApprovalFlow
  incidentDescription?: string
  incidentPostmortemLink?: string
}) {
  const { reload: reloadPage } = useContext(RemediationPageContext)
  const [checkedItemIndexes, setCheckedItemIndexes] = useState<number[]>([])
  const [formInstance] = form.useForm<SubmitFormData>()
  const checkItems = toPhase.checkItems || []
  useEffect(() => {
    setCheckedItemIndexes([])
  }, [ticket.id, ticket.appr_id, toPhase.name])
  const currentFlowNode =
    approvalFlow?.nodes?.find((node) => node.current) ||
    approvalFlow?.nodes?.find((node) => node.phase === toPhase.name)
  const hasInputFields =
    currentFlowNode?.requires_input ??
    (currentFlowNode?.action
      ? currentFlowNode.action ===
        EntityRemediationApprovalFlowNodeAction.approve_with_input
      : (toPhase.fieldList?.length || 0) > 0)
  useIncidentDescriptionRootCauseDefault(
    formInstance,
    toPhase,
    ticket,
    incidentDescription
  )
  useIncidentPostmortemAccidentReportDefault(
    formInstance,
    toPhase,
    ticket,
    incidentPostmortemLink
  )

  // action handlers
  const handleApprove = useCallback(async () => {
    let approveInput = {}
    if (hasInputFields) {
      try {
        await formInstance.validateFields()
        approveInput = buildSubmitPhaseReq(
          formInstance.getFieldsValue() as SubmitFormData,
          ticket.version
        )
      } catch {
        return
      }
    }

    Modal.confirm({
      title: hasInputFields
        ? 'Approve and submit stage info'
        : 'Approve request',
      closable: true,
      content: (
        <div>
          {hasInputFields ? (
            <p>
              Approve this request and submit the information below for{' '}
              <b>{toPhase.label}</b>?
            </p>
          ) : (
            <p>Approve this request and continue the remediation workflow?</p>
          )}
        </div>
      ),
      okText: hasInputFields ? 'Approve and submit' : 'Approve',
      async onOk() {
        try {
          await remediationTicketControllerApproveTicketPhase(ticket.id, {
            appr_id: ticket.appr_id ? ticket.appr_id : 0,
            version: ticket.version ? ticket.version : 0,
            ...approveInput
          })
          Modal.success({
            title: hasInputFields
              ? 'Approved and submitted'
              : 'Approval recorded',
            content: (
              <div>
                <p>
                  {hasInputFields
                    ? 'The approval and required stage information were submitted.'
                    : toPhase.isfinal
                    ? 'The approval was completed.'
                    : 'Your approval was recorded. The workflow will move forward after all required approvers approve it.'}
                </p>
              </div>
            ),
            onOk() {}
          })
          reloadPage && reloadPage()
        } catch (error) {
          Modal.error({
            title: error.response?.data?.errcode || 'Operation failed',
            content:
              error.response?.data?.errmsg ||
              (hasInputFields
                ? 'Approve and submit failed. Please refresh and try again.'
                : 'Approve failed. Please refresh and try again.')
          })
          reloadPage && reloadPage()
        }
      }
    })
  }, [formInstance, hasInputFields, ticket, toPhase, reloadPage])

  const handleReject = useCallback(async () => {
    Modal.confirm({
      title: 'Reject request',
      closable: true,
      content: (
        <div>
          <p>
            Reject this approval request? Please provide a reason for the
            submitter.
          </p>
          <Input.TextArea id="rejectMessageTextArea" rows={2} />
        </div>
      ),
      okText: 'Reject',
      async onOk() {
        try {
          // HACK: not a sound method to get text area value
          const rejectMessage = (
            document.getElementById(
              'rejectMessageTextArea'
            ) as HTMLInputElement | null
          )?.value

          await remediationTicketControllerRejectTicketPhase(ticket.id, {
            appr_id: ticket.appr_id ? ticket.appr_id : 0,
            version: ticket.version ? ticket.version : 0,
            message: rejectMessage
          })
          Modal.success({
            title: 'Request rejected',
            content: (
              <div>
                <p>The request was rejected and returned to the submitter.</p>
              </div>
            ),
            onOk() {}
          })
          reloadPage && reloadPage()
        } catch (error) {
          Modal.error({
            title: error.response?.data?.errcode || 'Reject failed',
            content:
              error.response?.data?.errmsg ||
              'Reject failed. Please refresh and try again.'
          })
          reloadPage && reloadPage()
        }
      }
    })
  }, [ticket, reloadPage])

  // return JSX element
  return (
    <div className="remediation-interactive-panel-inner">
      {toPhase.approvalInfo ? toPhase.approvalInfo() : defaultApprovalInfo}
      {checkItems.length > 0 && (
        <List
          size="small"
          dataSource={checkItems}
          renderItem={(item: React.ReactNode, index: number) => (
            <List.Item>
              <Checkbox
                checked={checkedItemIndexes.includes(index)}
                onChange={(e) => {
                  setCheckedItemIndexes((prev) =>
                    e.target.checked
                      ? [
                          ...prev.filter((itemIndex) => itemIndex !== index),
                          index
                        ]
                      : prev.filter((itemIndex) => itemIndex !== index)
                  )
                }}
              >
                {item}
              </Checkbox>
            </List.Item>
          )}
        />
      )}
      {hasInputFields && (
        <>
          <Typography.Title level={5}>
            {toPhase.label} information
          </Typography.Title>
          <Form form={formInstance} layout="vertical">
            {toPhase.getFields &&
              toPhase.getFields(formInstance, ticket, {
                requiresInput: hasInputFields
              })}
          </Form>
        </>
      )}
      <div
        className={clsx(
          'flex-container',
          'remediation-interactive-panel-buttons'
        )}
      >
        <Button
          type="primary"
          disabled={checkedItemIndexes.length !== checkItems.length}
          onClick={handleApprove}
        >
          {hasInputFields ? 'Approve and submit' : 'Approve'}
        </Button>
        &nbsp;
        <Button type="primary" onClick={handleReject}>
          Reject
        </Button>
      </div>
    </div>
  )
}

interface SubmitFormData {
  accident_report_link?: string
  /** Patch From RDG SLA Owner */
  accumulated_down_minutes?: string
  /** Patch From Global Deal Desk */
  cluster_billing?: string
  extra_percent?: string
  predefined_percent?: string
  total_compensation?: string
  /** Will be deprecated */
  reason?: string
  report_link?: string
  monthly_uptime_percentage?: string
  /** Patch From Region TSE Leader */
  root_cause_from_gs?: string
  root_cause_from_rdg?: string
}

const useIncidentDescriptionRootCauseDefault = (
  formInstance: FormInstance<SubmitFormData>,
  phaseInstance: PhaseInstance,
  ticket: EntityRemediationTicket,
  incidentDescription?: string
) => {
  useEffect(() => {
    if (
      phaseInstance.name !== EntityRemediationTicketPhase.region_tse_leader ||
      !incidentDescription ||
      ticket.root_cause_from_gs
    ) {
      return
    }

    const currentValue = formInstance.getFieldValue('root_cause_from_gs')
    if (!currentValue) {
      formInstance.setFieldsValue({
        root_cause_from_gs: incidentDescription
      })
    }
  }, [
    formInstance,
    incidentDescription,
    phaseInstance.name,
    ticket.root_cause_from_gs
  ])
}

const useIncidentPostmortemAccidentReportDefault = (
  formInstance: FormInstance<SubmitFormData>,
  phaseInstance: PhaseInstance,
  ticket: EntityRemediationTicket,
  incidentPostmortemLink?: string
) => {
  useEffect(() => {
    const isPostmortemDoc =
      incidentPostmortemLink?.includes('/docx/') ||
      incidentPostmortemLink?.includes('/wiki/')

    if (
      phaseInstance.name !== EntityRemediationTicketPhase.rdg_sla_owner ||
      !incidentPostmortemLink ||
      !isPostmortemDoc ||
      ticket.accident_report_link
    ) {
      return
    }

    const currentValue = formInstance.getFieldValue('accident_report_link')
    if (!currentValue) {
      formInstance.setFieldsValue({
        accident_report_link: incidentPostmortemLink
      })
    }
  }, [
    formInstance,
    incidentPostmortemLink,
    phaseInstance.name,
    ticket.accident_report_link
  ])
}

const buildSubmitPhaseReq = (
  formData: SubmitFormData,
  version?: number
): RemediationticketSubmitTicketPhaseReq => ({
  accident_report_link: formData.accident_report_link,
  accumulated_down_minutes:
    formData.accumulated_down_minutes === undefined
      ? undefined
      : Number(formData.accumulated_down_minutes),
  cluster_billing: formData.cluster_billing,
  extra_percent: '0',
  total_compensation: formData.total_compensation,
  report_link: formData.report_link,
  root_cause_from_gs: formData.root_cause_from_gs,
  root_cause_from_rdg: formData.root_cause_from_rdg,
  version
})

const RemediationSubmitForm = function ({
  ticket,
  phaseInstance,
  incidentDescription,
  incidentPostmortemLink
}: {
  ticket: EntityRemediationTicket
  phaseInstance: PhaseInstance
  incidentDescription?: string
  incidentPostmortemLink?: string
}) {
  const { reload: reloadPage } = useContext(RemediationPageContext)

  const [formInstance] = form.useForm<SubmitFormData>()
  useIncidentDescriptionRootCauseDefault(
    formInstance,
    phaseInstance,
    ticket,
    incidentDescription
  )
  useIncidentPostmortemAccidentReportDefault(
    formInstance,
    phaseInstance,
    ticket,
    incidentPostmortemLink
  )
  // action handlers
  const handleFinish = useCallback(
    async (formData: SubmitFormData) => {
      const req = buildSubmitPhaseReq(formData, ticket.version)
      await remediationTicketControllerSubmitTicketPhase(ticket.id, req)
    },
    [ticket]
  )

  const submitForm = useCallback(async () => {
    Modal.confirm({
      title: 'Submit stage info',
      closable: true,
      content: (
        <div>
          <p>Submit this stage and start the next approval request?</p>
        </div>
      ),
      okText: 'Submit',
      async onOk() {
        try {
          await formInstance.validateFields()
          await handleFinish(formInstance.getFieldsValue() as SubmitFormData)
          Modal.success({
            title: 'Stage submitted',
            content: (
              <div>
                <p>The next approval request has been started.</p>
              </div>
            ),
            onOk() {}
          })
          reloadPage && reloadPage()
        } catch (error) {
          Modal.error({
            title: error.response?.data?.errcode || 'Submit failed',
            content:
              error.response?.data?.errmsg ||
              'Submit failed. Please refresh and try again.'
          })
          reloadPage && reloadPage()
        }
      }
    })
  }, [formInstance, handleFinish, reloadPage])

  const handleClose = useCallback(async () => {
    Modal.confirm({
      title: 'Close ticket',
      closable: true,
      content: (
        <div>
          <p>Close this remediation ticket without continuing the workflow?</p>
        </div>
      ),
      okText: 'Close ticket',
      async onOk() {
        try {
          await remediationTicketControllerCancelTicket(ticket.id)
          Modal.success({
            title: 'Ticket closed',
            content: (
              <div>
                <p>The remediation ticket has been closed.</p>
              </div>
            ),
            onOk() {}
          })
          reloadPage && reloadPage()
        } catch (error) {
          Modal.error({
            title: error.response?.data?.errcode || 'Close failed',
            content:
              error.response?.data?.errmsg ||
              'Close failed. Please refresh and try again.'
          })
          reloadPage && reloadPage()
        }
      }
    })
  }, [ticket, reloadPage])

  // return value
  return (
    <div className="remediation-interactive-panel-inner">
      {phaseInstance.getFields ? (
        <Form form={formInstance} layout="vertical" onFinish={handleFinish}>
          {phaseInstance.getFields &&
            phaseInstance.getFields(formInstance, ticket, {
              requiresInput: true
            })}
        </Form>
      ) : (
        <Typography>
          No additional information is required for this stage. Submit to start
          the next approval request.
        </Typography>
      )}
      <div
        className={clsx(
          'flex-container',
          'remediation-interactive-panel-buttons'
        )}
      >
        <Button type="primary" onClick={submitForm}>
          Submit
        </Button>
        &nbsp;
        <Button type="primary" onClick={handleClose}>
          Close
        </Button>
      </div>
    </div>
  )
}

const RemediationViewerPanel = function ({
  ticket,
  currUserEmail,
  ticketApprovals
}: {
  ticket: EntityRemediationTicket
  currUserEmail: string
  ticketApprovals?: EntityRemediationTicketPhaseApproval[]
}) {
  if (ticket.phase === EntityRemediationTicketPhase.succeed)
    return (
      <div className="remediation-interactive-panel-inner">
        <Result status="success" title="The ticket is now approved"></Result>
      </div>
    )
  else if (ticket.phase === EntityRemediationTicketPhase.closed)
    return (
      <div className="remediation-interactive-panel-inner">
        <Result
          title={`The ticket is closed and archived`}
          subTitle={`Please create a new ticket if needed`}
        ></Result>
      </div>
    )
  else {
    let phaseLabel: string | undefined = ''
    if (
      ticket.status === EntityRemediationTicketStatus.approving &&
      ticketApprovals &&
      ticket.appr_id
    ) {
      const currentTicketApproval = findTicketApprovalByID(
        ticketApprovals,
        ticket.appr_id
      )
      phaseLabel =
        currentTicketApproval &&
        getPhaseByName(currentTicketApproval.to_phase)?.label
    } else {
      phaseLabel = ticket.phase && getPhaseByName(ticket.phase)?.label
    }
    return (
      <div className="remediation-interactive-panel-inner">
        <Result
          title={`The ticket is pending at ${phaseLabel}`}
          subTitle={`${ticket.current_responsible_person_email} is now processing the ticket.`}
        ></Result>
      </div>
    )
  }
}

export { RemediationTicketInteractPanel }
