import { PlusOutlined } from '@ant-design/icons'
import { Button, Modal, Tabs } from 'antd'
import Table, { ColumnsType } from 'antd/lib/table'
import { useCallback, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'

import {
  clusterServiceCreateClusterOpsMaintenanceWindow,
  createMaintenance,
  clusterServiceDeleteClusterOpsMaintenanceWindow,
  clusterServiceListClusterOpsMaintenanceWindows,
  listMaintenances,
  clusterServiceUpdateClusterOpsMaintenanceWindow
} from 'apiClient/services/devops'
import {
  ClusterCreateMaintenanceReq,
  ListMaintenancesParams,
  ClusterServiceListClusterOpsMaintenanceWindowsParams,
  MaintenanceClusterMaintenance,
  MaintenanceClusterOpsMaintenanceWindow,
  MaintenanceClusterOpsMaintenanceWindowSlot
} from 'apiClient/services/devops/interface'
import ModalForm from 'components/ModalForm'
import SearchBar from 'components/SearchBar'
import { ListToolBar, useTable } from 'components/Table'

import {
  ClusterOpsMaintenanceWindowFormValues,
  renderClusterOpsMaintenanceWindowForm
} from './ClusterOpsMaintenanceWindowForm'
import CreateMaitenanceForm, { MaintenanceForm } from './CreateMaintenanceForm'
import { toLocal } from './Detail'

enum MaintenanceTabs {
  ClusterMaintenance = 'cluster_maintenance',
  ClusterOpsMaintenanceWindows = 'cluster_ops_maintenance_windows'
}

enum ClusterOpsMaintenanceWindowModalType {
  Create = 'create',
  Edit = 'edit'
}

const { TabPane } = Tabs

export const ClusterMaintenance = () => {
  const [createForm, setCreateForm] = useState(false)
  const [searchParams, setSearchParams] = useState<ListMaintenancesParams>({
    project_ids: []
  })

  const getData = (params?: Partial<PageInfo>) =>
    listMaintenances({
      page: params?.page,
      per_page: params?.pageSize,
      project_ids: searchParams.project_ids
    })

  const { dataSource, loading, reload, paginationProps, onTableChange } =
    useTable<ListData<MaintenanceClusterMaintenance>>(getData, [], {
      pagination: true
    })

  const reloadInit = () => {
    setSearchParams({ statues: ['Pending', 'Running'], project_ids: [] })
    return reload()
  }

  const handleCreate = useCallback(
    async (payload: MaintenanceForm) => {
      const req: ClusterCreateMaintenanceReq = {
        cluster_ids: payload.cluster_ids,
        description: payload.description,
        deadline: payload.deadline.unix(),
        project_id: payload.project_id
      }
      return createMaintenance(req).then(() => {
        setCreateForm(false)
        reload()
      })
    },
    [reload]
  )

  const onSearch = (query: { project_id: string }) => {
    if (query == undefined || query.project_id == '') {
      return reloadInit()
    }
    setSearchParams({ statues: [], project_ids: [query.project_id] })
    return reload()
  }

  const handleCancel = useCallback(() => {
    setCreateForm(false)
  }, [])

  const renderFormFields = useCallback(() => {
    return <CreateMaitenanceForm />
  }, [createForm])

  const columns: ColumnsType<MaintenanceClusterMaintenance> = [
    {
      title: 'ID',
      render: (_: any, record) => {
        return record.id
      }
    },
    {
      title: 'Project ID',
      render: (_: any, record) => {
        return record.task?.project_id
      }
    },
    {
      title: 'Schedule Time',
      render: (_: any, record) => {
        return toLocal(record.task?.schedule_time)
      }
    },
    {
      title: 'Status',
      render: (_: any, record) => {
        return record.task?.status
      }
    },
    {
      title: 'Action',
      render: (_: any, record) => {
        return (
          <Button type="primary">
            <Link to={`/maintenance/${record.id}`}>Detail</Link>
          </Button>
        )
      }
    }
  ]
  const actions = useMemo(
    () => [
      <SearchBar
        defaultValue={{
          project_id: ''
        }}
        options={['project_id']}
        labels={['Project ID']}
        fetcher={onSearch}
      />,
      <Button
        type="primary"
        name="create"
        icon={<PlusOutlined />}
        onClick={() => {
          setCreateForm(true)
        }}
      >
        Create
      </Button>
    ],
    []
  )

  return (
    <div>
      <ListToolBar actions={actions} reload={reloadInit} />

      <Table<MaintenanceClusterMaintenance>
        columns={columns}
        rowKey="id"
        dataSource={dataSource}
        loading={loading}
        pagination={paginationProps}
        size="small"
        onChange={onTableChange}
      ></Table>

      <ModalForm<MaintenanceForm>
        visible={!!createForm}
        name="user"
        title={'create a new maintenance window'}
        getFields={renderFormFields}
        onSubmit={handleCreate}
        onCancel={handleCancel}
      />
    </div>
  )
}

const formatWindows = (
  windows: MaintenanceClusterOpsMaintenanceWindow['windows']
) => {
  if (!windows || windows.length === 0) {
    return '-'
  }

  return windows
    .map((slot) => {
      const startCronSpec = slot.start_cron_spec?.trim() || '-'
      const duration = slot.duration?.trim() || '-'

      return `${startCronSpec} | ${duration}`
    })
    .join('\n')
}

const formatApprovers = (
  approvers: MaintenanceClusterOpsMaintenanceWindow['approvers']
) => {
  if (!approvers || approvers.length === 0) {
    return '-'
  }

  return approvers.join(', ')
}

export const ClusterOpsMaintenanceWindows = () => {
  const [searchParams, setSearchParams] =
    useState<ClusterServiceListClusterOpsMaintenanceWindowsParams>({
      cluster_ids: []
    })
  const [modalType, setModalType] =
    useState<ClusterOpsMaintenanceWindowModalType>()
  const [editRecord, setEditRecord] =
    useState<MaintenanceClusterOpsMaintenanceWindow>()
  const [viewRecord, setViewRecord] =
    useState<MaintenanceClusterOpsMaintenanceWindow>()

  const getData = (params?: Partial<PageInfo>) =>
    clusterServiceListClusterOpsMaintenanceWindows({
      page: params?.page,
      per_page: params?.pageSize,
      cluster_ids: searchParams.cluster_ids
    })

  const { dataSource, loading, reload, paginationProps, onTableChange } =
    useTable<ListData<MaintenanceClusterOpsMaintenanceWindow>>(getData, [], {
      pagination: true,
      deps: [searchParams]
    })

  const formInitValues = useMemo(() => {
    if (modalType === ClusterOpsMaintenanceWindowModalType.Edit && editRecord) {
      return {
        approvers: editRecord.approvers || [],
        cluster_id: editRecord.cluster_id || '',
        windows:
          editRecord.windows && editRecord.windows.length > 0
            ? editRecord.windows
            : [{ description: '', start_cron_spec: '', duration: '' }]
      }
    }

    return {
      approvers: [],
      cluster_id: '',
      windows: [{ description: '', start_cron_spec: '', duration: '' }]
    }
  }, [editRecord, modalType])

  const reloadInit = () => {
    if (searchParams.cluster_ids && searchParams.cluster_ids.length > 0) {
      setSearchParams({ cluster_ids: [] })
      return Promise.resolve()
    }

    return reload()
  }

  const handleCreate = useCallback(() => {
    setEditRecord(undefined)
    setModalType(ClusterOpsMaintenanceWindowModalType.Create)
  }, [])

  const handleEdit = useCallback(
    (record: MaintenanceClusterOpsMaintenanceWindow) => {
      setEditRecord(record)
      setModalType(ClusterOpsMaintenanceWindowModalType.Edit)
    },
    []
  )

  const handleCloseModal = useCallback(() => {
    setEditRecord(undefined)
    setModalType(undefined)
  }, [])

  const handleView = useCallback(
    (record: MaintenanceClusterOpsMaintenanceWindow) => {
      setViewRecord(record)
    },
    []
  )

  const handleCloseView = useCallback(() => {
    setViewRecord(undefined)
  }, [])

  const handleDelete = useCallback(
    async (record: MaintenanceClusterOpsMaintenanceWindow) => {
      const clusterId = record.cluster_id

      if (!clusterId) {
        return
      }

      Modal.confirm({
        title: 'Delete Maintenance Window',
        content: `sure to delete maintenance window for cluster ${clusterId}?`,
        okButtonProps: {
          danger: true
        },
        onOk: async () => {
          try {
            await clusterServiceDeleteClusterOpsMaintenanceWindow(clusterId)
            await reload()
          } catch (error) {
            window.alert('fail to delete the cluster ops maintenance window')
          }
        }
      })
    },
    [reload]
  )

  const handleSubmit = useCallback(
    async (payload: ClusterOpsMaintenanceWindowFormValues) => {
      const approvers = (payload.approvers || [])
        .map((item) => item.trim())
        .filter(Boolean)

      if (
        modalType === ClusterOpsMaintenanceWindowModalType.Edit &&
        payload.cluster_id
      ) {
        await clusterServiceUpdateClusterOpsMaintenanceWindow(
          payload.cluster_id,
          {
            approvers,
            windows: payload.windows
          }
        )
      } else {
        await clusterServiceCreateClusterOpsMaintenanceWindow({
          approvers,
          cluster_id: payload.cluster_id,
          windows: payload.windows
        })
      }

      handleCloseModal()
      await reload()
    },
    [handleCloseModal, modalType, reload]
  )

  const onSearch = useCallback(async (query: { cluster_id: string } | null) => {
    if (query === null || query.cluster_id === '') {
      setSearchParams({ cluster_ids: [] })
      return Promise.resolve()
    }

    setSearchParams({ cluster_ids: [query.cluster_id] })
    return Promise.resolve()
  }, [])

  const viewWindowColumns: ColumnsType<MaintenanceClusterOpsMaintenanceWindowSlot> =
    useMemo(
      () => [
        {
          title: (
            <div>
              <div>Cron Spec (UTC+0)</div>
              <div style={{ fontSize: 12, color: '#8c8c8c' }}>
                Cron expression of window start time.
              </div>
            </div>
          ),
          dataIndex: 'start_cron_spec',
          render: (value: string | undefined) => value || '-'
        },
        {
          title: (
            <div>
              <div>Duration</div>
              <div style={{ fontSize: 12, color: '#8c8c8c' }}>
                {'String format of time.Duration, e.g. "1h", "50m".'}
              </div>
            </div>
          ),
          dataIndex: 'duration',
          render: (value: string | undefined) => value || '-'
        },
        {
          title: (
            <div>
              <div>Description</div>
              <div style={{ fontSize: 12, color: '#8c8c8c' }}>
                Description of this maintenance window.
              </div>
            </div>
          ),
          dataIndex: 'description',
          render: (value: string | undefined) => value || '-'
        }
      ],
      []
    )

  const columns: ColumnsType<MaintenanceClusterOpsMaintenanceWindow> = [
    {
      title: 'ID',
      render: (_: any, record) => {
        return record.id
      }
    },
    {
      title: 'Cluster ID',
      render: (_: any, record) => {
        return record.cluster_id
      }
    },
    {
      title: 'Windows (UTC+0)',
      render: (_: any, record) => {
        return (
          <div style={{ whiteSpace: 'pre-line' }}>
            {formatWindows(record.windows)}
          </div>
        )
      }
    },
    {
      title: 'Approvers',
      render: (_: any, record) => {
        return formatApprovers(record.approvers)
      }
    },
    {
      title: 'Created At',
      render: (_: any, record) => {
        return toLocal(record.created_at)
      }
    },
    {
      title: 'Actions',
      render: (_: any, record) => (
        <div style={{ display: 'flex', gap: 8 }}>
          <Button
            type="link"
            size="small"
            style={{ padding: '0 4px' }}
            onClick={() => handleView(record)}
          >
            View
          </Button>
          <Button
            type="link"
            size="small"
            style={{ padding: '0 4px' }}
            onClick={() => handleEdit(record)}
          >
            Edit
          </Button>
          <Button
            type="link"
            size="small"
            danger
            style={{ padding: '0 4px' }}
            onClick={() => handleDelete(record)}
          >
            Delete
          </Button>
        </div>
      )
    }
  ]

  const actions = useMemo(
    () => [
      <SearchBar
        defaultValue={{
          cluster_id: ''
        }}
        options={['cluster_id']}
        labels={['Cluster ID']}
        fetcher={onSearch}
      />,
      <Button type="primary" icon={<PlusOutlined />} onClick={handleCreate}>
        Create
      </Button>
    ],
    [handleCreate, onSearch]
  )

  return (
    <div>
      <ListToolBar actions={actions} reload={reloadInit} />

      <Table<MaintenanceClusterOpsMaintenanceWindow>
        columns={columns}
        rowKey={(record) => String(record.id || record.cluster_id)}
        dataSource={dataSource}
        loading={loading}
        pagination={paginationProps}
        size="small"
        onChange={onTableChange}
      ></Table>

      <ModalForm<ClusterOpsMaintenanceWindowFormValues>
        visible={!!modalType}
        name="cluster-ops-maintenance-window"
        width={800}
        labelAlign="left"
        title={
          modalType === ClusterOpsMaintenanceWindowModalType.Edit
            ? 'Edit ClusterOpsMaintenanceWindow'
            : 'Create ClusterOpsMaintenanceWindow'
        }
        initValues={formInitValues}
        getFields={() =>
          renderClusterOpsMaintenanceWindowForm({
            editable: modalType !== ClusterOpsMaintenanceWindowModalType.Edit,
            initValues: formInitValues
          })
        }
        onSubmit={handleSubmit}
        onCancel={handleCloseModal}
      />

      <Modal
        open={!!viewRecord}
        width={800}
        title="View ClusterOpsMaintenanceWindow"
        footer={null}
        onCancel={handleCloseView}
      >
        <div style={{ marginBottom: 12 }}>
          <strong>Cluster ID: </strong>
          {viewRecord?.cluster_id || '-'}
        </div>
        <div style={{ marginBottom: 12 }}>
          <strong>Approvers: </strong>
          {formatApprovers(viewRecord?.approvers)}
        </div>
        <Table<MaintenanceClusterOpsMaintenanceWindowSlot>
          columns={viewWindowColumns}
          dataSource={viewRecord?.windows || []}
          rowKey={(_, index) => String(index)}
          pagination={false}
          size="small"
        />
      </Modal>
    </div>
  )
}

export const Maintenance = () => {
  return (
    <Tabs defaultActiveKey={MaintenanceTabs.ClusterMaintenance}>
      <TabPane
        tab="Cluster Maintenances"
        key={MaintenanceTabs.ClusterMaintenance}
      >
        <ClusterMaintenance />
      </TabPane>
      <TabPane
        tab="Cluster Ops MaintenanceWindows"
        key={MaintenanceTabs.ClusterOpsMaintenanceWindows}
      >
        <ClusterOpsMaintenanceWindows />
      </TabPane>
    </Tabs>
  )
}

export default Maintenance
