import { GlobalOutlined, LockOutlined, ReloadOutlined } from '@ant-design/icons'
import { json as jsonLang } from '@codemirror/lang-json'
import CodeMirror from '@uiw/react-codemirror'
import {
  Alert,
  Button,
  Card,
  Empty,
  Form,
  List,
  Modal,
  Space,
  Spin,
  Table,
  Tag,
  Typography,
  message
} from 'antd'
import { detailedDiff } from 'deep-object-diff'
import type { DetailedDiff } from 'deep-object-diff'
import type { ReactNode } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useLocation } from 'react-router-dom'

import {
  regionControllerGetRegion,
  regionControllerUpdateRegion
} from 'apiClient/services/devops'
import { RegionRegion } from 'apiClient/services/devops/interface/regionRegion'
import { TenantDetailLinkPopover } from 'components/DetailLinkPopover/TenantDetailLinkPopover'

import { getDefaultProviderIdentities } from './defaultProviderIdentity'
import UpdateRegionForm, {
  UpdateRegionFormValues,
  buildUpdateRegionInitialValues,
  buildUpdateRegionRequest
} from './Forms/UpdateRegionForm'
import { renderRegionState, renderServicePlanTag } from './helper'
import { getRegionWhiteLists } from './regionWhiteList'

const { Text } = Typography

const BASIC_LABEL_WIDTH = 160

const DELETED_SENTINEL = '__DELETED__'
const LEGACY_DELETED_REGION_CHANGE_FIELDS = new Set([
  'is_public',
  'opened_tenant_ids',
  'service_plan',
  'enableOpenedTenantIds'
])

type RegionChangedPayload = Record<string, unknown> & {
  deleted?: Record<string, unknown>
}

const sanitizeUpdateRegionChanged = (
  changedValues: DetailedDiff
): RegionChangedPayload => {
  const changedPayload = changedValues as unknown as RegionChangedPayload
  const deleted = changedPayload.deleted
  if (!deleted || typeof deleted !== 'object' || Array.isArray(deleted)) {
    return changedPayload
  }

  const nextDeleted = { ...(deleted as Record<string, unknown>) }
  let removed = false
  LEGACY_DELETED_REGION_CHANGE_FIELDS.forEach((field) => {
    if (field in nextDeleted && nextDeleted[field] === undefined) {
      delete nextDeleted[field]
      removed = true
    }
  })

  if (!removed) {
    return changedPayload
  }

  const nextChangedValues: RegionChangedPayload = { ...changedPayload }
  if (Object.keys(nextDeleted).length === 0) {
    delete nextChangedValues.deleted
  } else {
    nextChangedValues.deleted = nextDeleted
  }

  return nextChangedValues
}

export default function RegionDetail() {
  const location = useLocation()
  const searchParams = useMemo(
    () => new URLSearchParams(location.search),
    [location.search]
  )
  const logical_name = searchParams.get('logical_name') ?? undefined
  const cloudProvider = searchParams.get('cloud_provider') ?? undefined
  const deployType = searchParams.get('deploy_type') ?? undefined
  const servicePlan = searchParams.get('service_plan') ?? undefined
  const isByocServicePlan = servicePlan === 'BYOC'
  const isUpdateRegionSupportedDeployType =
    deployType === 'DEPLOY_TYPE_SERVERLESS' ||
    deployType === 'DEPLOY_TYPE_NEXTGEN'
  const canUpdateRegion =
    isUpdateRegionSupportedDeployType && !isByocServicePlan
  const isNextgenDeployType = deployType === 'DEPLOY_TYPE_NEXTGEN'

  const [region, setRegion] = useState<RegionRegion | null>(null)
  const [loading, setLoading] = useState(false)
  const [updateModalVisible, setUpdateModalVisible] = useState(false)
  const [updating, setUpdating] = useState(false)
  const [updateForm] = Form.useForm<UpdateRegionFormValues>()

  const fetchRegion = useCallback(async () => {
    if (!cloudProvider || !logical_name) {
      setRegion(null)
      return
    }

    try {
      setLoading(true)
      const { data } = await regionControllerGetRegion({
        cloud_provider: cloudProvider,
        logical_name,
        deploy_type: deployType ?? undefined,
        service_plan: servicePlan ?? undefined
      })
      setRegion(data.region ?? null)
    } catch (error) {
      const err = error as any
      const errMsg =
        err?.response?.data?.errmsg ??
        err?.message ??
        'Failed to load region detail'
      message.error(errMsg)
    } finally {
      setLoading(false)
    }
  }, [cloudProvider, deployType, logical_name, servicePlan])

  useEffect(() => {
    fetchRegion()
  }, [fetchRegion])

  const regionSpec = useMemo(() => region?.region, [region])
  const regionWhiteLists = useMemo(
    () => getRegionWhiteLists(regionSpec),
    [regionSpec]
  )
  const useRegionWhiteListMode = regionWhiteLists.length > 0
  const updateInitialValues = useMemo<
    Partial<UpdateRegionFormValues> | undefined
  >(() => {
    if (!region) {
      return undefined
    }
    return buildUpdateRegionInitialValues(region)
  }, [region])
  const defaultProviderIdentities = useMemo(
    () => getDefaultProviderIdentities(region),
    [region]
  )

  const handleOpenUpdateModal = () => {
    updateForm.resetFields()
    setUpdateModalVisible(true)
  }

  const handleCloseUpdateModal = () => {
    setUpdateModalVisible(false)
  }

  const handleUpdateSubmit = async () => {
    try {
      const values = await updateForm.validateFields()
      const changedValues = detailedDiff(
        buildUpdateRegionInitialValues(region),
        values
      )
      const sanitizedChangedValues = sanitizeUpdateRegionChanged(changedValues)
      const payload = buildUpdateRegionRequest(
        values,
        JSON.stringify(sanitizedChangedValues, (key, value) =>
          value === undefined ? DELETED_SENTINEL : value
        )
      )
      setUpdating(true)

      var resp = (await regionControllerUpdateRegion(payload)).data.instance_id

      Modal.success({
        title: 'Update Region Operation Created',
        content: (
          <div>
            <p>
              Operation <b>{resp}</b> is awaiting approval and can only be
              started after approval.
              <br></br>
              <br></br>
              To check the progress of this operation, please refer to the{' '}
              <a href={`/operations/${resp}`}>Detail</a> page.
            </p>
          </div>
        ),
        onOk() {
          window.open(`/operations/${resp}`, '_blank')
        }
      })

      setUpdateModalVisible(false)
      fetchRegion()
    } catch (error) {
      if ((error as { errorFields?: unknown[] })?.errorFields) {
        return
      }
      const err = error as any
      const errMsg =
        err?.response?.data?.errmsg ?? err?.message ?? 'Failed to update region'
      message.error(errMsg)
    } finally {
      setUpdating(false)
    }
  }

  if (!cloudProvider || !logical_name) {
    return (
      <Alert
        showIcon
        type="warning"
        message="Missing parameters"
        description="cloud_provider (query) and logical_name (path) are required to load region detail."
      />
    )
  }

  if (loading || !region) {
    return <Spin size="large" spinning tip="Loading region detail..." />
  }

  return (
    <div>
      <Space direction="vertical" size="large" style={{ width: '100%' }}>
        <Card
          title={
            <span style={{ fontSize: 20, fontWeight: 600 }}>Region Detail</span>
          }
          extra={
            <Space>
              <Button
                type="primary"
                onClick={handleOpenUpdateModal}
                disabled={!canUpdateRegion}
              >
                Update
              </Button>
              <Button
                icon={<ReloadOutlined />}
                onClick={fetchRegion}
                loading={loading}
              />
            </Space>
          }
        >
          <Space direction="vertical" size={24} style={{ width: '100%' }}>
            <Card size="small" title="Region Basics">
              <div
                style={{
                  display: 'grid',
                  gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
                  gap: '10px 24px'
                }}
              >
                {renderBasicField('Logical Name', regionSpec?.logical_name)}
                {renderBasicField('Region ID', regionSpec?.id)}
                {renderBasicField('Display Name', regionSpec?.display_name)}
                {renderBasicField(
                  'Cloud Provider',
                  regionSpec?.cloud_provider_id
                )}
                {renderBasicField(
                  'State',
                  renderRegionState(regionSpec?.state)
                )}
                {renderBasicField('Deploy Type', region.deploy_type)}
                {renderBasicField('Area', regionSpec?.area)}
                {renderBasicField('Country Code', regionSpec?.country_code)}
                {renderBasicField('Sort Priority', regionSpec?.sort_priority)}
                {!useRegionWhiteListMode &&
                  renderBasicField(
                    'Is Public',
                    regionSpec?.is_public ? 'Yes' : 'No'
                  )}
                {!useRegionWhiteListMode &&
                  renderBasicField(
                    'Service Plan',
                    renderServicePlanTag(regionSpec?.service_plan)
                  )}
                {renderBasicField(
                  'Default Backup Time',
                  regionSpec?.default_backup_time
                )}
                {renderBasicField(
                  'Service Address',
                  regionSpec?.service_address
                )}
                {renderBasicField(
                  'Shared Bucket URL',
                  regionSpec?.shared_bucket_url,
                  <Text type="secondary">Not configured</Text>
                )}
              </div>
            </Card>

            <Card size="small" title="Service Plan Visibility">
              {useRegionWhiteListMode ? (
                <>
                  <Text type="secondary">
                    Public means the service plan is open to all tenants.
                    Private + Opened Tenant IDs means only those tenants can use
                    this service plan.
                  </Text>
                  <div style={{ marginTop: 12 }}>
                    {renderRegionWhiteLists(regionWhiteLists)}
                  </div>
                </>
              ) : (
                <>
                  <Text strong>Opened Tenant IDs</Text>
                  <div style={{ marginTop: 12 }}>
                    {renderTenantIdsList(
                      regionSpec?.opened_tenant_ids,
                      'No tenant is explicitly opened for this region'
                    )}
                  </div>
                </>
              )}
            </Card>

            {isNextgenDeployType && (
              <Card size="small" title="Default Provider Identities">
                <Text type="secondary">
                  This is the cloud account identity used by a tenant in this
                  region. `tenant_id = 0` means region-level default for that
                  service plan.
                </Text>
                <div style={{ marginTop: 12 }}>
                  {renderDefaultProviderIdentities(defaultProviderIdentities)}
                </div>
              </Card>
            )}

            {deployType !== 'DEPLOY_TYPE_SERVERLESS' && (
              <Card size="small" title="Ops Audit Log Setting">
                {renderJSONBlock(
                  regionSpec?.ops_audit_log_setting,
                  'Ops audit log setting not configured'
                )}
              </Card>
            )}
          </Space>
        </Card>
      </Space>
      <Modal
        title="Update Region"
        width={920}
        open={updateModalVisible}
        onCancel={handleCloseUpdateModal}
        onOk={handleUpdateSubmit}
        okText="Update"
        confirmLoading={updating}
        maskClosable={false}
        destroyOnClose
      >
        <UpdateRegionForm
          form={updateForm}
          initialValues={updateInitialValues}
          formProps={{
            preserve: false
          }}
        />
      </Modal>
    </div>
  )
}

function renderDefaultProviderIdentities(
  identities: {
    tenant_id?: string
    identity?: string
    service_plan?: string
  }[]
) {
  if (!identities || identities.length === 0) {
    return (
      <div style={{ padding: '24px 0' }}>
        <Empty
          description="No default provider identity configured"
          image={Empty.PRESENTED_IMAGE_SIMPLE}
        />
      </div>
    )
  }

  return (
    <Table
      size="small"
      pagination={false}
      dataSource={identities}
      rowKey={(item, index) =>
        `${item.service_plan || ''}-${item.tenant_id || ''}-${
          item.identity || ''
        }-${index}`
      }
      columns={[
        {
          title: 'Service Plan',
          dataIndex: 'service_plan',
          key: 'service_plan',
          width: 200,
          render: (servicePlan: string | undefined) =>
            renderServicePlanTag(servicePlan)
        },
        {
          title: 'Tenant ID',
          dataIndex: 'tenant_id',
          key: 'tenant_id',
          width: 160,
          render: (tenantId: string | undefined) => tenantId || '-'
        },
        {
          title: 'Provider Identity',
          dataIndex: 'identity',
          key: 'identity',
          render: (identity: string | undefined) => identity || '-'
        }
      ]}
      scroll={{ x: 680 }}
    />
  )
}

function renderRegionWhiteLists(
  regionWhiteLists: {
    service_plan?: string
    is_public?: boolean
    opened_tenant_ids?: string[]
  }[]
) {
  if (regionWhiteLists.length === 0) {
    return (
      <Empty
        description="No region white list found"
        image={Empty.PRESENTED_IMAGE_SIMPLE}
      />
    )
  }

  return (
    <List
      split={false}
      dataSource={regionWhiteLists}
      renderItem={(item) => (
        <List.Item style={{ padding: '8px 0' }}>
          <Card size="small" style={{ width: '100%' }}>
            <Space direction="vertical" size={10} style={{ width: '100%' }}>
              <Space align="center" size={12}>
                {renderServicePlanTag(item.service_plan)}
                <Tag
                  color={item.is_public ? 'success' : 'default'}
                  icon={item.is_public ? <GlobalOutlined /> : <LockOutlined />}
                  style={{ marginInlineEnd: 0 }}
                >
                  {item.is_public ? 'Public' : 'Private'}
                </Tag>
              </Space>
              {!item.is_public && (
                <div>
                  <Text type="secondary">Opened Tenant IDs</Text>
                  <div style={{ marginTop: 8 }}>
                    {renderTenantIdsList(
                      item.opened_tenant_ids,
                      'No tenant is explicitly opened for this service plan',
                      {
                        inline: true,
                        compactEmpty: true
                      }
                    )}
                  </div>
                </div>
              )}
            </Space>
          </Card>
        </List.Item>
      )}
    />
  )
}

function renderJSONBlock(value: unknown | undefined, emptyText: string) {
  if (value == undefined) {
    return (
      <div style={{ minHeight: 96, padding: '16px 0' }}>
        <Empty description={emptyText} image={Empty.PRESENTED_IMAGE_SIMPLE} />
      </div>
    )
  }

  let content = ''
  try {
    content = JSON.stringify(value, null, 2) ?? ''
  } catch (error) {
    content = String(value)
  }

  return (
    <CodeMirror
      value={content}
      editable={false}
      extensions={[jsonLang()]}
      basicSetup={{
        lineNumbers: true,
        foldGutter: true,
        highlightActiveLine: false
      }}
      style={{
        border: '1px solid #d9d9d9',
        borderRadius: 4,
        fontSize: 12,
        overflow: 'hidden'
      }}
    />
  )
}

function renderTenantIdsList(
  tenantIds: string[] | undefined,
  emptyText: string,
  options?: {
    inline?: boolean
    compactEmpty?: boolean
  }
) {
  if (!tenantIds || tenantIds.length === 0) {
    return (
      <div style={{ padding: options?.compactEmpty ? '24px 0' : '0' }}>
        <Empty description={emptyText} image={Empty.PRESENTED_IMAGE_SIMPLE} />
      </div>
    )
  }

  if (options?.inline) {
    return (
      <Space size={[8, 8]} wrap>
        {tenantIds.map((tenantId) => (
          <Tag key={tenantId}>
            <TenantDetailLinkPopover tenantId={tenantId} text={tenantId} />
          </Tag>
        ))}
      </Space>
    )
  }

  return (
    <List
      dataSource={tenantIds}
      renderItem={(tenantId) => (
        <List.Item>
          <Space>
            <TenantDetailLinkPopover tenantId={tenantId} text={tenantId} />
          </Space>
        </List.Item>
      )}
    />
  )
}

function renderBasicField(
  label: string,
  value: ReactNode,
  emptyFallback?: ReactNode
) {
  const hasValue = value !== undefined && value !== null && value !== ''
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start' }}>
      <Text
        type="secondary"
        style={{
          width: BASIC_LABEL_WIDTH,
          flexShrink: 0,
          paddingRight: 12,
          color: 'rgba(0, 0, 0, 0.45)'
        }}
      >
        {label}
      </Text>
      <div
        style={{
          color: 'rgba(0, 0, 0, 0.88)',
          minWidth: 0,
          wordBreak: 'break-word'
        }}
      >
        {hasValue ? value : emptyFallback || '-'}
      </div>
    </div>
  )
}
