import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
import {
  Divider,
  Input,
  Form,
  Select,
  Button,
  Descriptions,
  Tag,
  Space,
  Tooltip,
  Typography,
  Card,
  Tabs,
  DatePicker,
  Badge,
  message,
  Skeleton
} from 'antd'
import TextArea from 'antd/lib/input/TextArea'
import moment from 'moment'
import { useCallback, useState } from 'react'
import { useParams } from 'react-router-dom'
import useProfileContext from 'useProfileContext'

import { generateFeishuMessage } from 'apiClient/api'
import {
  createIncidentLogItem,
  updateIncident,
  useGetIncident,
  useGetIncidentComponentOptions
} from 'apiClient/services/devops'
import {
  EntityIncident,
  EntityIncidentLogItem
} from 'apiClient/services/devops/interface'
import { useWorkspaceHandlerGetWorkspace } from 'apiClient/services/ticket-manager'
import ModalForm from 'components/ModalForm'
import { UserSearchInput } from 'components/ResourceSearchInput/DevOps/UserSearchInput'
import { WorkspaceSearchInput } from 'components/ResourceSearchInput/TicketManager/WorkspaceSearchInput'

import IncidentLog from '../IncidentLog'
import { EventCreationForm } from '../IncidentLog/eventForm'
import IncidentPostMortem from '../IncidentPostMortem'
import {
  AntdIncidentEditAdaptor,
  antdIncidentEditAdaptorConvertToUpdateIncidentReq,
  calculateTTR,
  formsIncidentConvertToAntdIncident,
  fallbackIncidentComponents,
  regionColors,
  statusColors,
  statusText,
  tierColors
} from '../Util'

const jiraRE = [/ONCALL-\d+/, /TCOC-\d+/, /GTOC-\d+/, /O11Y-\d+/]

function getJiraIssueIdFromLink(link: string): string {
  for (let i = 0; i < jiraRE.length; i++) {
    let re = jiraRE[i]
    let arr = re.exec(link)
    if (arr) return arr[0]
  }
  return 'unknown'
}

function getIncidentJiraLinks(
  record: Pick<EntityIncident, 'jira_issue_links' | 'jira_issues'>
) {
  if (record.jira_issue_links && record.jira_issue_links.length > 0) {
    return record.jira_issue_links
      .map((item) => ({
        href: item.url,
        label:
          item.key || (item.url ? getJiraIssueIdFromLink(item.url) : 'unknown')
      }))
      .filter((item): item is { href: string; label: string } => !!item.href)
  }

  return (
    record.jira_issues
      ?.split(' ')
      .filter((item) => item.length > 0)
      .map((item) => ({ href: item, label: getJiraIssueIdFromLink(item) })) ||
    []
  )
}

function toUTCPickerMoment(value?: string | moment.Moment | null) {
  if (!value) {
    return null
  }

  if (moment.isMoment(value)) {
    return value.clone().utc()
  }

  return moment.utc(value)
}

function normalizePickerValueToUTC(value: moment.Moment | null) {
  if (!value) {
    return null
  }

  return moment.utc({
    year: value.year(),
    month: value.month(),
    date: value.date(),
    hour: value.hour(),
    minute: value.minute(),
    second: value.second(),
    millisecond: 0
  })
}

const utcStartOfDay = moment.utc().startOf('day')

function IncidentEdit({
  record,
  reload,
  onCancel,
  componentOptions
}: {
  record: EntityIncident
  reload: () => void
  onCancel: Function
  componentOptions: string[]
}) {
  const [submitting, setSubmitting] = useState<boolean>(false)
  //const [errors, setErrors] = useState<string[] | null>(null)

  const [form] = Form.useForm()

  const handleFinish = async () => {
    try {
      const values = await form.validateFields()
      const record = antdIncidentEditAdaptorConvertToUpdateIncidentReq(
        values as AntdIncidentEditAdaptor
      )

      console.log('incident submitted:', record)

      setSubmitting(true)

      try {
        await updateIncident(values.id || -1, record)
      } catch (e) {
        console.error(e)
        //setErrors([
        //  e?.response?.data?.message ||
        //    e?.response?.data?.error ||
        //    e?.message ||
        //    JSON.stringify(e)
        //])
      }
      reload()
    } catch (err) {
      console.warn('Validate failed:', err)
      message.warn('update incident failed:', err)
    } finally {
      setSubmitting(false)
    }
  }

  var recordData = formsIncidentConvertToAntdIncident(record)
  if (!recordData) {
    return null
  }

  return (
    <Form initialValues={recordData} onFinish={handleFinish} form={form}>
      <Form.Item name="id" label="id" hidden>
        <Input type="hidden" />
      </Form.Item>
      <Form.Item name="name" label="Incident Name">
        <Input />
      </Form.Item>
      <Form.Item name="status" label="Status">
        <Select
          style={{ width: 120 }}
          options={[
            { value: 'ongoing', label: 'Ongoing' },
            { value: 'post-mortem', label: 'Post Mortem' },
            { value: 'under-improvement', label: 'Under Improvement' },
            { value: 'archived', label: 'Archived' }
          ]}
        />
      </Form.Item>
      <Form.Item name="tier" label="Incident Tier">
        <Select
          style={{ width: 120 }}
          options={[
            { value: 't0', label: 'T0' },
            { value: 't1', label: 'T1' },
            { value: 't2', label: 'T2' },
            { value: 't3', label: 'T3' }
          ]}
        />
      </Form.Item>
      <Form.Item name="biz_regions" label="Biz Regions">
        <Select
          mode="multiple"
          style={{ width: 120 }}
          options={[
            { value: 'jp', label: 'Japan' },
            { value: 'na', label: 'NA' },
            { value: 'apac', label: 'APAC' },
            { value: 'emea', label: 'EMEA' }
          ]}
        />
      </Form.Item>
      <Form.Item name="components" label="Component(s)">
        <Select
          mode="multiple"
          allowClear
          style={{ width: '100%' }}
          placeholder="Please select"
          options={componentOptions.map((c) => {
            return { label: c, value: c }
          })}
        />
      </Form.Item>
      <Form.Item name="oncallers" label="Oncaller(s)">
        <UserSearchInput mode="multiple" style={{ width: 400 }} />
      </Form.Item>
      <Form.Item name="leaders" label="Team Leader(s)">
        <UserSearchInput mode="multiple" style={{ width: 400 }} />
      </Form.Item>
      <Form.Item name="fbowners" label="FB Owner">
        <UserSearchInput mode="multiple" style={{ width: 120 }} />
      </Form.Item>
      <Form.Item name="war_room_id" label="Associated War Room">
        <WorkspaceSearchInput style={{ width: '100%' }} />
      </Form.Item>
      <Form.Item label="Jira Issues">
        <Form.List name="jira_issues">
          {(fields, { add, remove }, { errors }) => (
            <>
              {fields.map((field, index) => (
                <>
                  <Form.Item key={field.key}>
                    <Form.Item
                      {...field}
                      rules={[
                        {
                          required: true,
                          whitespace: true,
                          message: 'Please input a valid Jira URL'
                        }
                      ]}
                      noStyle
                    >
                      <Input style={{ width: 500 }}></Input>
                    </Form.Item>
                    <MinusCircleOutlined onClick={() => remove(field.name)} />
                  </Form.Item>
                </>
              ))}
              <Form.Item>
                <Button
                  type="dashed"
                  onClick={() => add()}
                  style={{ width: 500 }}
                  icon={<PlusOutlined />}
                >
                  Add Jira Issue
                </Button>
                <Form.ErrorList errors={errors} />
              </Form.Item>
            </>
          )}
        </Form.List>
      </Form.Item>
      <Form.Item name="feishu_url" label="Feishu Links">
        <Input />
      </Form.Item>
      <Form.Item
        name="incident_start_time"
        label="Incident Start Time (UTC)"
        getValueProps={(i) => ({ value: toUTCPickerMoment(i) })}
        getValueFromEvent={(value) => normalizePickerValueToUTC(value)}
      >
        <DatePicker
          format="YYYY-MM-DD HH:mm:ss"
          showTime={{ defaultValue: utcStartOfDay }}
        ></DatePicker>
      </Form.Item>
      <Form.Item
        name="incident_resolve_time"
        label="Incident Resolve Time (UTC)"
        getValueProps={(i) => ({ value: toUTCPickerMoment(i) })}
        getValueFromEvent={(value) => normalizePickerValueToUTC(value)}
      >
        <DatePicker
          format="YYYY-MM-DD HH:mm:ss"
          showTime={{ defaultValue: utcStartOfDay }}
        ></DatePicker>
      </Form.Item>
      <Form.Item name="description" label="Description">
        <TextArea rows={4} />
      </Form.Item>
      <Form.Item>
        <Space direction="horizontal">
          <Button type="primary" htmlType="submit" loading={submitting}>
            Save
          </Button>
          <Button onClick={() => onCancel()}>Cancel</Button>
        </Space>
      </Form.Item>
    </Form>
  )
}

function IncidentViewOnly({
  record,
  editable,
  onEdit
}: {
  record: EntityIncident
  editable: boolean
  onEdit: Function
}) {
  const [generateFeishuButtonLoading, setGenerateFeishuButtonLoading] =
    useState<boolean>(false)
  const warRoomId = record.war_room_id
  const { data: workspaceResponse } = useWorkspaceHandlerGetWorkspace(
    warRoomId ?? 0,
    {
      query: {
        enabled: warRoomId != null,
        refetchOnWindowFocus: false,
        refetchInterval: false
      }
    }
  )
  const workspace = workspaceResponse?.data.workspace

  var recordData = record
  const renderTagsFromString = useCallback((s: string, color: string) => {
    var substrings = s.split(' ')
    return substrings.map((s) => <Tag color={color}>{s}</Tag>)
  }, [])

  const renderTagsForBizRegion = useCallback((s: string) => {
    var regions = s.split(' ')
    return regions.map((region) => (
      <Tag color={regionColors[region] ? regionColors[region] : 'purple'}>
        {region === 'jp' ? 'Japan' : region.toUpperCase()}
      </Tag>
    ))
  }, [])

  const renderTagsForTier = useCallback((s: string) => {
    return (
      <Tag color={tierColors[s] ? tierColors[s] : 'default'}>
        {s.toUpperCase()}
      </Tag>
    )
  }, [])

  const renderBadgesForStatus = useCallback((s: string) => {
    return (
      <Tag color="default">
        <Badge
          color={statusColors[s] ? statusColors[s] : 'grey'}
          text={statusText[s] ? statusText[s] : 'Unknown'}
        />
      </Tag>
    )
  }, [])

  const genFeishu = async () => {
    // TODO: add generate function
    console.log('generate feishu message for incident', record.id)
    setGenerateFeishuButtonLoading(true)
    try {
      await generateFeishuMessage(record.id ? record.id.toString() : '-1')
      message.success('send feishu message succeeded')
    } catch (e) {
      console.error(e)
      message.error('send feishu message failed')
    } finally {
      setGenerateFeishuButtonLoading(false)
    }
  }

  return (
    <>
      <Descriptions title={recordData.name}>
        <Descriptions.Item label="Incident Tier">
          {recordData.tier ? renderTagsForTier(recordData.tier) : ''}
        </Descriptions.Item>
        <Descriptions.Item label="Status">
          {recordData.status ? renderBadgesForStatus(recordData.status) : ''}
        </Descriptions.Item>
        <Descriptions.Item label="Biz Regions">
          {recordData.biz_regions
            ? renderTagsForBizRegion(recordData.biz_regions)
            : ''}
        </Descriptions.Item>
        <Descriptions.Item label="Component(s)">
          {recordData.components
            ? renderTagsFromString(recordData.components, 'blue')
            : ''}
        </Descriptions.Item>
        <Descriptions.Item label="Associated War Room">
          {workspace ? (
            <Typography.Link
              href={`https://ticket-manager.ops.pingcap.net/workspaces/${warRoomId}`}
              target="_blank"
              rel="noopener noreferrer"
            >
              {workspace.name} #{warRoomId}
            </Typography.Link>
          ) : (
            warRoomId ?? '-'
          )}
        </Descriptions.Item>
        <Descriptions.Item label="Incident Start Time (UTC)">
          {recordData.incident_start_time}
        </Descriptions.Item>
        <Descriptions.Item label="Incident Resolve Time (UTC)">
          {recordData.incident_resolve_time}
        </Descriptions.Item>
        {record.incident_resolve_time && (
          <Descriptions.Item label="TTR">
            {calculateTTR(
              record.incident_start_time!,
              record.incident_resolve_time
            )}{' '}
            minutes
          </Descriptions.Item>
        )}
        <Descriptions.Item label="Description">
          {recordData.description}
        </Descriptions.Item>
      </Descriptions>
      <Divider />
      <Descriptions title="Involved Persons">
        <Descriptions.Item label="Oncaller(s)">
          <Space size="middle">
            {record.oncallers?.map((person) => (
              <>{person.lark_user_name}</>
            ))}
          </Space>
        </Descriptions.Item>
        <Descriptions.Item label="Team Leader(s)">
          <Space size="large">
            {record.leaders?.map((person) => (
              <>{person.lark_user_name}</>
            ))}
          </Space>
        </Descriptions.Item>
        <Descriptions.Item label="FB Owner">
          <Space size="large">
            {record.fbowners?.map((person) => (
              <>{person.lark_user_name}</>
            ))}
          </Space>
        </Descriptions.Item>
      </Descriptions>
      <Divider />
      <Descriptions title="Useful Links">
        <Descriptions.Item label="Jira Issues" span={12}>
          <Space size="middle">
            {getIncidentJiraLinks(record).map((item) => (
              <Typography.Link href={item.href} target="_blank">
                {item.label}
              </Typography.Link>
            ))}
          </Space>
        </Descriptions.Item>
        <Descriptions.Item label="Feishu Link">
          {record.feishu_url && record.feishu_url.indexOf('/chat/') !== -1 ? (
            <Typography.Link href={record.feishu_url}>
              Click to join feishu group
            </Typography.Link>
          ) : (
            ''
          )}
        </Descriptions.Item>
      </Descriptions>
      <Divider />
      <Space direction="horizontal">
        <Button onClick={() => onEdit()} disabled={!editable}>
          Edit
        </Button>

        <Button
          onClick={() => genFeishu()}
          loading={generateFeishuButtonLoading}
        >
          Generate Feishu Channel Message
        </Button>
      </Space>
    </>
  )
}

export default function IncidentDetail() {
  const { incident_id } = useParams<{ incident_id: string }>()
  const { data, refetch } = useGetIncident(Number(incident_id), {
    query: { refetchOnWindowFocus: false, refetchInterval: false }
  })
  const { data: componentOptionsResp } = useGetIncidentComponentOptions({
    query: { refetchOnWindowFocus: false, refetchInterval: false }
  })
  const [loading, setLoading] = useState<boolean>(false)
  const [editing, setEditing] = useState<boolean>(false)
  const [activeTab, setActiveTab] = useState<'1' | '2'>('1')
  const [modalOpen, setModalOpen] = useState<'none' | 'event' | 'postmortem'>(
    'none'
  )
  const {
    profile: { roles }
  } = useProfileContext()
  const editable = !!roles?.admin
  const componentOptions =
    componentOptionsResp?.data.components ?? fallbackIncidentComponents

  const renderEventFormFields = useCallback(() => {
    return <EventCreationForm />
  }, [])

  const handleEventCancel = useCallback(() => {
    setModalOpen('none')
  }, [])

  const handleEventCreate = useCallback(
    async (payload: EntityIncidentLogItem) => {
      return createIncidentLogItem(parseInt(incident_id), payload).then(() => {
        setModalOpen('none')
      })
    },
    [incident_id]
  )

  const reload = async () => {
    try {
      setLoading(true)
      await refetch()
      setEditing(false)
      setModalOpen('none')
    } catch (e) {
      console.log('refetch record failed', e)
      message.warn('renew record failed')
    } finally {
      setLoading(false)
    }
  }

  var record: EntityIncident
  if (!data) {
    return null
  } else {
    record = data.data
  }

  if (loading) return <Skeleton></Skeleton>
  else
    return (
      <div
        className="incident-detail-container"
        style={{ backgroundColor: 'rgba(240,242,245,1)', margin: '0px' }}
      >
        <Space direction="vertical" size="large" style={{ display: 'flex' }}>
          <Card
            id="incident-summary"
            style={{
              borderRadius: '8px',
              boxShadow: 'rgba(0, 0, 0, 0.04) 0px 2px 4px'
            }}
          >
            <Space
              direction="vertical"
              size="middle"
              style={{ display: 'flex' }}
            >
              {editing ? (
                <IncidentEdit
                  record={record}
                  onCancel={() => setEditing(false)}
                  reload={reload}
                  componentOptions={componentOptions}
                />
              ) : (
                <IncidentViewOnly
                  record={record}
                  editable={editable}
                  onEdit={() => setEditing(!editing)}
                />
              )}
            </Space>
          </Card>
          <Card
            id="incident-timeline-postmortem"
            style={{
              borderRadius: '8px',
              boxShadow: 'rgba(0, 0, 0, 0.04) 0px 2px 4px'
            }}
          >
            <Tabs
              activeKey={activeTab}
              onChange={(key) => setActiveTab(key as '1' | '2')}
              type="card"
            >
              <Tabs.TabPane tab="Event Timeline" key="1">
                <IncidentLog incident_id={incident_id} record={record} />
                <Button
                  type="primary"
                  disabled={!editable}
                  onClick={() => {
                    setModalOpen('event')
                  }}
                >
                  Create Event
                </Button>
                <Tooltip title="Current Unavailable">
                  <Button disabled={!editable}>Sync from Feishu</Button>
                </Tooltip>
                <ModalForm<EntityIncidentLogItem>
                  initValues={{
                    item_type: 'general',
                    event_time: new Date().toISOString()
                  }}
                  visible={modalOpen === 'event'}
                  name="incident event"
                  title="create a new incident event"
                  getFields={renderEventFormFields}
                  onSubmit={handleEventCreate}
                  onCancel={handleEventCancel}
                />
              </Tabs.TabPane>
              <Tabs.TabPane tab="PostMortem" key="2">
                <IncidentPostMortem
                  incidentId={incident_id}
                  incident={record}
                  editable={editable}
                  reload={reload}
                />
              </Tabs.TabPane>
            </Tabs>
          </Card>
        </Space>
      </div>
    )
}
