import { Typography } from '@tidbcloud/uikit'
import { isEqual, difference as lodashDifference } from 'lodash-es'
import { ReactNode } from 'react'

import {
  DataflowBackupSettingActionType,
  DataflowBackupSettingStatus,
  DataflowQueryBackupSettingResp,
  DataflowRegionInfo,
  DataflowSnapshotBackupScheduleType,
  DataflowWeekDay,
  ModifyBackupSettingV2Body
} from 'dbaas/services/dataflow/interface'

import { toLocalBackupTime, toLocalWeekdays } from './utils'

export const defaultValues = {
  auto_backup_enable: true,
  schedule_type: DataflowSnapshotBackupScheduleType.Daily as DataflowSnapshotBackupScheduleType,
  backup_time: '00:00',
  retention_period: 7,
  pitr: false,
  weekdays: [DataflowWeekDay.SUNDAY] as DataflowWeekDay[],
  dual_region: false,
  selected_dual_region: ''
}

export type SettingFormValuesV2 = typeof defaultValues

export const FieldDisableWarnings = {
  DualRegionOrPointInTimeExclusiveChange: `Point-in-Time Restore and Dual Region Backup settings cannot be modified simultaneously. Please adjust one setting and wait for it to fully complete before modifying the other.`,
  WeeklyScheduleMustEnablePitr: `Point-in-time restore will be automatically enabled if opt-in weekly backup schedule.`
}

type State = { pitr: boolean; dualRegion: boolean }

export function matchFormChangeState(from: State, to: State, { dualRegionName }: { dualRegionName?: string }) {
  const warning1 = (
    <div>
      Starting from next backup time, the Point-in-Time Restore will take effect. However, if you trigger a manual
      backup immediately, you can experience Point-in-Time Restore instantly, eliminating the need to wait for the next
      scheduled backup task.
    </div>
  )
  const warning2 = (
    <div>
      Starting from that time, all backups will be automatically copied to the {dualRegionName ?? 'other region'}.
      However, if you trigger a manual backup immediately, you can experience cross region restoration instantly,
      eliminating the need to wait for the next scheduled backup task.
    </div>
  )
  const warning3 = (
    <div>
      We recommend enabling both <b>Point-in-Time Restore</b> and <b>Dual Region Backup</b> to achieve RPO {'<'} 5min
      for cross-region recovery. Note that these settings must be configured sequentially, as backend processing may
      take several hours to complete.
    </div>
  )
  const map = new Map<[State, State], ReactNode>([
    [
      [
        { pitr: false, dualRegion: false },
        { pitr: true, dualRegion: false }
      ],
      <Typography>{warning1}</Typography>
    ],
    [
      [
        { pitr: false, dualRegion: false },
        { pitr: false, dualRegion: true }
      ],
      <Typography>
        {warning2}
        {warning3}
      </Typography>
    ],
    [
      [
        { pitr: true, dualRegion: false },
        { pitr: true, dualRegion: true }
      ],
      <Typography>{warning2}</Typography>
    ],
    [
      [
        { pitr: false, dualRegion: true },
        { pitr: true, dualRegion: true }
      ],
      <Typography>{warning1}</Typography>
    ],
    [
      [
        { pitr: true, dualRegion: true },
        { pitr: true, dualRegion: false }
      ],
      <Typography>Starting from that time, all backups will be stored in the same region as the cluster.</Typography>
    ]
  ])

  for (const key of map.keys()) {
    if (isEqual(key, [from, to])) {
      return map.get(key)
    }
  }
}

export const getSettingStatusWarning = (
  status: DataflowBackupSettingStatus,
  ops: DataflowBackupSettingActionType[],
  pitr: boolean
): string => {
  const unavailableOps = lodashDifference(
    [
      DataflowBackupSettingActionType.Edit_PiTR,
      DataflowBackupSettingActionType.Edit_Region,
      DataflowBackupSettingActionType.Edit_Schedule
    ],
    ops
  )
  const map = {
    [DataflowBackupSettingActionType.Edit_Region]: 'editing Dual Region',
    [DataflowBackupSettingActionType.Edit_PiTR]: 'editing Point-in-time Restore',
    [DataflowBackupSettingActionType.Edit_Schedule]: 'editing backup policy'
  }
  const text =
    unavailableOps.length > 0
      ? `, ${unavailableOps.map((i) => map[i]).join(' and ')} ${unavailableOps.length > 1 ? 'are' : 'is'} not allowed`
      : ''
  return {
    [DataflowBackupSettingStatus.Editing_PiTR]: `Point-in-time Restore change is not complete${text}.`,
    [DataflowBackupSettingStatus.Editing_Region]: `Dual Region change is not complete${text}.`,
    [DataflowBackupSettingStatus.Waiting_For_Editing_PiTR]: pitr
      ? `Point-in-Time Restore will take effect at next backup${text}. However, if you trigger a manual backup immediately, you can experience Point-in-Time Restore instantly, eliminating the need to wait for the next scheduled backup task`
      : ''
  }[status as any]
}

export function toFormValues(data: DataflowQueryBackupSettingResp, timezone: number): typeof defaultValues {
  const type = data.snapshot_backup_schedule?.schedule_type
  const isWeekly = type === DataflowSnapshotBackupScheduleType.Weekly
  const isDaily = type === DataflowSnapshotBackupScheduleType.Daily
  const backupTime = (function () {
    if (isDaily) {
      return data.snapshot_backup_schedule?.daily_schedule_time!
    } else if (isWeekly) {
      return data.snapshot_backup_schedule?.weekly_schedule?.schedule_time!
    }
    return defaultValues.backup_time
  })()

  return {
    auto_backup_enable: !data.snapshot_backup_schedule?.disable,
    schedule_type: type!,
    backup_time: toLocalBackupTime(backupTime, timezone),
    retention_period: Number(data.snapshot_backup_schedule?.retention_policy?.retention_period),
    pitr: data.continuous_backup_schedule?.enable!,
    weekdays: isWeekly
      ? toLocalWeekdays(data.snapshot_backup_schedule?.weekly_schedule?.days!, backupTime, timezone)
      : ([DataflowWeekDay.SUNDAY] as DataflowWeekDay[]),
    dual_region: (data.regions?.length ?? 1) >= 2,
    selected_dual_region: data.regions?.[1]?.name ?? ''
  }
}

export function fromFormValues(
  data: typeof defaultValues,
  clusterRegion: DataflowRegionInfo,
  backupRegion?: DataflowRegionInfo
): ModifyBackupSettingV2Body {
  return {
    snapshot_backup_schedule: {
      disable: !data.auto_backup_enable,
      schedule_type: data.schedule_type,
      daily_schedule_time:
        data.schedule_type === DataflowSnapshotBackupScheduleType.Daily ? data.backup_time : undefined,
      weekly_schedule:
        data.schedule_type === DataflowSnapshotBackupScheduleType.Weekly
          ? {
              days: data.weekdays,
              schedule_time: data.backup_time
            }
          : undefined,
      retention_policy: {
        retention_period: data.retention_period + ''
      }
    },
    continuous_backup_schedule: {
      enable: data.pitr
    },
    regions: data.dual_region ? [clusterRegion, backupRegion!].filter(Boolean) : [clusterRegion]
  }
}
