import { log } from 'console'

import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
import {
  Button,
  Checkbox,
  Col,
  Divider,
  Form,
  FormInstance,
  Input,
  Radio,
  RadioChangeEvent,
  Row,
  Select
} from 'antd'
import TextArea from 'antd/lib/input/TextArea'
import { ColumnsType } from 'antd/lib/table'
import { useEffect, useState } from 'react'

import {
  githubControllerListRepositories,
  githubControllerRawDiffRelease,
  githubControllerRawListLabels,
  githubControllerRawListPullRequests,
  githubControllerRawListReleases
} from 'apiClient/services/devops'
import { GithubPullRequest } from 'apiClient/services/devops/interface'
import DebounceSelect from 'components/DebounceSelect/DebounceSelect'

import { APP_DELIVERY_REPO } from '../helper'

const org = 'tidbcloud'

export type PRFormType = {
  prs: GithubPullRequest[]
}

const noExistInArray = (val: string, arr: { location: string }[]) => {
  for (const element of arr) {
    if (element.location === val) {
      return false
    }
  }
  return true
}

function extractTitle(str: string): string {
  const match = /:(.*)/.exec(str)
  if (match && match.length > 1) {
    return match[1]
  }
  return ''
}

export const PRForm = ({ form }: { form: FormInstance }) => {
  const handleChangeResource = async (val: RadioChangeEvent) => {
    setResource(val.target.value)
    setAlternativePRs([])
    form.setFieldsValue({ alternatives: [] })
  }
  const [resource, setResource] = useState<string>('tag')
  const [alternativePRs, setAlternativePRs] = useState<
    { label: string; value: string }[]
  >([])
  const [repos, setRepos] = useState<{ label: string; value: string }[]>([])
  const [tags, setTags] = useState<{ label: string; value: string }[]>([])
  const [labels, setLabels] = useState<{ label: string; value: string }[]>([])

  useEffect(() => {
    const setRepoOptinos = async () => {
      if (resource !== 'input') {
        const data =
          (
            await githubControllerListRepositories({
              owners: [org],
              page: 1,
              per_page: 30
            })
          ).data.repositories || []
        setRepos(
          data.map((val) => {
            return { label: val.name || '', value: val.name || '' }
          })
        )
      }
      form.setFieldsValue({ repo: null })
      form.setFieldsValue({ prev: null })
      form.setFieldsValue({ target: null })
      form.setFieldsValue({ labels: [] })
    }
    setRepoOptinos()
  }, [resource])

  interface LabelValue {
    label: string
    value: string
  }

  async function fetchRepo(reponame: string): Promise<LabelValue[]> {
    return githubControllerListRepositories({
      owners: [org],
      page: 1,
      per_page: 30,
      location_like: reponame
    })
      .then((val) => {
        return val.data.repositories
      })
      .then((data) => {
        return (data || []).map((val) => {
          return { label: val.location || '', value: val.name || '' }
        })
      })
  }

  const handleAddPRs = () => {
    var totalAdd = []
    const origin = form.getFieldValue(['prs'])
    if (resource === 'input') {
      const toAdd = form.getFieldValue(['inputPR'])
      const regex = /https:\/\/github.com\/([^\/]+)\/([^\/]+)\/pull\/(\d+)/
      const match = toAdd.match(regex)

      if (match) {
        const [link, owner, repo, number] = match
        totalAdd = [
          {
            location: `${owner}/${repo}#${number}`,
            owner,
            repo,
            number: parseInt(number),
            title: link
          }
        ]
      } else {
        window.alert(
          'the PR link is not in correct format, please fill in again'
        )
      }
    } else {
      const toAddString = form.getFieldValue(['alternatives'])
      const toAdd = toAddString.map((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 {
            location,
            owner,
            repo,
            number: parseInt(number),
            title: extractTitle(
              alternativePRs.filter((val) => {
                return val.value === location
              })[0].label
            )
          }
        }
      })
      totalAdd = toAdd
    }
    const filtered = totalAdd.filter((val: { location: string }) => {
      return noExistInArray(val.location, origin)
    })
    form.setFieldsValue({ prs: [...origin, ...filtered] })
    setAlternativePRs([])
    form.setFieldsValue({ alternatives: [] })
  }

  const handleRepoTagChange = async (val: LabelValue) => {
    const data =
      (await githubControllerRawListReleases(org, val.value, { per_page: 10 }))
        .data.releases || []
    setTags(
      data.map((val) => {
        return { label: val.tag_name || '', value: val.tag_name || '' }
      })
    )
    form.setFieldsValue({ prev: null })
    form.setFieldsValue({ target: null })
    setAlternativePRs([])
    form.setFieldsValue({ alternatives: [] })
  }

  const handleRepoLabelChange = async (val: LabelValue) => {
    const data =
      (await githubControllerRawListLabels(org, val.value, { per_page: 10 }))
        .data.labels || []
    setLabels(
      data.map((val) => {
        return { label: val.name || '', value: val.name || '' }
      })
    )
    form.setFieldsValue({ labels: [] })
    setAlternativePRs([])
    form.setFieldsValue({ alternatives: [] })
  }

  const handleSearchByTag = async () => {
    const data =
      (
        await githubControllerRawDiffRelease(
          org,
          form.getFieldValue(['repo']).value,
          {
            prev: form.getFieldValue(['prev']),
            target: form.getFieldValue(['target'])
          }
        )
      ).data.pull_requests || []
    setAlternativePRs(
      data.map((val) => {
        return {
          label: '#' + val.number + ' ' + val.state + ': ' + val.title,
          value: '' + val.location
        }
      })
    )
  }

  const handleSearchByLabels = async () => {
    const data =
      (
        await githubControllerRawListPullRequests(
          org,
          form.getFieldValue(['repo']).value,
          { labels: form.getFieldValue(['labels']) }
        )
      ).data.pull_requests || []
    setAlternativePRs(
      data.map((val) => {
        return {
          label: '#' + val.number + ' ' + val.state + ': ' + val.title,
          value: '' + val.location
        }
      })
    )
  }

  const handleSelectAllAlternative = () => {
    const allAlternatives = alternativePRs.map((val) => {
      return val.value
    })
    form.setFieldsValue({ alternatives: allAlternatives })
  }

  return (
    <div>
      <Form.Item
        style={{ marginLeft: 0 }}
        name="source"
        label="Source"
        rules={[{ required: true, message: 'Method for PR is required' }]}
        initialValue={resource}
      >
        <Radio.Group onChange={handleChangeResource}>
          <Radio value={'tag'}>Generated From Tag</Radio>
          <Radio value={'filter'}>Search PRs</Radio>
          <Radio value={'input'}>Input PRs</Radio>
        </Radio.Group>
      </Form.Item>
      {resource === 'input' ? (
        <Row gutter={16}>
          <Col style={{ marginLeft: 100 }} span={16}>
            <Form.Item name="inputPR" label="Input PR">
              <Input
                placeholder={`pr link like https://github.com/${APP_DELIVERY_REPO()}/pull/5123`}
              ></Input>
            </Form.Item>
          </Col>
        </Row>
      ) : resource === 'tag' ? (
        <>
          <Form.Item name="repo" label="Repo" required={true}>
            <DebounceSelect
              showSearch
              placeholder="Please type to search repository's name"
              fetchOptions={fetchRepo}
              onChange={handleRepoTagChange}
            />
          </Form.Item>
          <Form.Item name="target" label="Target Tag">
            <Select options={tags}></Select>
          </Form.Item>
          <Form.Item name="prev" label="Previous Tag">
            <Select options={tags}></Select>
          </Form.Item>
          <div
            className="flex-container"
            style={{ justifyContent: 'flex-end', display: 'flex' }}
          >
            <Button type="primary" onClick={handleSearchByTag}>
              Generate
            </Button>
          </div>
        </>
      ) : (
        <>
          <Form.Item name="repo" label="Repo" required={true}>
            <DebounceSelect
              showSearch
              placeholder="Please type to search repository's name"
              fetchOptions={fetchRepo}
              onChange={handleRepoLabelChange}
            />
          </Form.Item>
          <Form.Item name="labels" label="Labels">
            <Select mode="multiple" options={labels}></Select>
          </Form.Item>
          <div
            className="flex-container"
            style={{ justifyContent: 'flex-end', display: 'flex' }}
          >
            <Button type="primary" onClick={handleSearchByLabels}>
              Search
            </Button>
          </div>
        </>
      )}

      {resource === 'input' ? (
        <></>
      ) : (
        <div>
          <Divider></Divider>
          <div>
            <Form.Item label={<b>Alternative PRs</b>} name={'alternatives'}>
              <Checkbox.Group
                options={alternativePRs}
                style={{
                  width: '100%',
                  display: 'flex',
                  flexDirection: 'column'
                }}
              />
            </Form.Item>
          </div>
        </div>
      )}

      <div
        className="flex-container"
        style={{ justifyContent: 'flex-end', display: 'flex' }}
      >
        {resource !== `input` ? (
          <Button onClick={handleSelectAllAlternative}>Select All</Button>
        ) : (
          <></>
        )}
        &nbsp;&nbsp;&nbsp;
        <Button type="primary" onClick={handleAddPRs}>
          Add
        </Button>
      </div>

      <Divider></Divider>

      <Form.Item
        name={'prs_list'}
        label={<b>Selected PRs</b>}
        style={{ marginLeft: 0 }}
        labelCol={{ span: 0 }}
      >
        <Row gutter={16}>
          <Col span={4}>PR</Col>
          <Col span={18}>Title/Description</Col>
          <Col span={2}>Action</Col>
        </Row>
        <Form.List name={'prs'}>
          {(fields, { add, remove }, { errors }) => (
            <>
              {fields.map(({ key, name, ...restField }, index) => (
                <div key={key}>
                  <Row gutter={16}>
                    <Col span={4}>
                      <Form.Item
                        {...restField}
                        name={[name, 'pr_description']}
                        style={{ marginBottom: '3px', marginTop: '3px' }}
                        // initialValue={'https://github.com/' + form.getFieldValue(['prs', 0, 'owner']) + '/' + form.getFieldValue(['prs', 0, 'repo']) + "/pull/" + form.getFieldValue(['prs', 0, 'number'])}
                      >
                        <p>
                          <a
                            href={
                              'https://github.com/' +
                              form.getFieldValue(['prs', index, 'owner']) +
                              '/' +
                              form.getFieldValue(['prs', index, 'repo']) +
                              '/pull/' +
                              form.getFieldValue(['prs', index, 'number'])
                            }
                            target="_blank"
                            rel="noreferrer"
                          >
                            {form.getFieldValue(['prs', name, 'location'])}
                          </a>
                        </p>
                      </Form.Item>
                    </Col>
                    <Col span={18}>
                      <Form.Item
                        {...restField}
                        name={[name, 'title']}
                        rules={[{ required: true }]}
                        style={{ marginBottom: '3px', marginTop: '3px' }}
                      >
                        <TextArea disabled={true} bordered={false}></TextArea>
                      </Form.Item>
                    </Col>
                    <Col span={2}>
                      <MinusCircleOutlined
                        className="dynamic-delete-button"
                        onClick={() => remove(name)}
                        style={{ marginBottom: '3px', marginTop: '3px' }}
                      />
                    </Col>
                  </Row>
                  <Divider
                    style={{ marginBottom: '3px', marginTop: '3px' }}
                  ></Divider>
                </div>
              ))}
            </>
          )}
        </Form.List>
      </Form.Item>
    </div>
  )
}

export default PRForm
