import { t } from '#cli/i18n'
import { TBox, TDialog, TInput, TText, wrapByCells } from '@simon_he/vue-tui'
import { defineComponent, h, ref, watch } from 'vue'
import { useUiTheme } from '../theme'
import { withFocusedInputTip } from './input-clear-tip'

export const DimSdkProviderConnectDialog = defineComponent({
  name: 'DimSdkProviderConnectDialog',
  props: {
    modelValue: { type: Boolean, required: true },
    providerName: { type: String, default: '' },
    w: { type: Number, default: 70 },
    h: { type: Number, default: 16 },
    baseUrl: { type: String, default: '' },
    apiKeyDraft: { type: String, default: '' },
    apiKeyMasked: { type: String, default: '' },
    focusKey: { type: Boolean, default: false },
    baseUrlMode: { type: String, default: 'editable' },
    showBaseUrl: { type: Boolean, default: true },
    showApiKey: { type: Boolean, default: true },
    canClearKey: { type: Boolean, default: false },
    baseUrlAfterApiKey: { type: Boolean, default: false },
    applying: { type: Boolean, default: false },
    backdrop: { type: Boolean, default: false },
  },
  emits: {
    'update:modelValue': (_v: boolean) => true,
    'update:baseUrl': (_v: string) => true,
    'update:apiKeyDraft': (_v: string) => true,
    'apply': () => true,
    'clearKey': () => true,
    'cancel': () => true,
  },
  setup(props, { emit }) {
    const ui = useUiTheme()
    const focusedField = ref<'baseUrl' | 'apiKey' | null>(null)
    const resolveBaseUrlMode = (): 'editable' | 'readonly' | 'hidden' => {
      if (props.baseUrlMode === 'readonly' || props.baseUrlMode === 'hidden')
        return props.baseUrlMode
      return props.showBaseUrl ? 'editable' : 'hidden'
    }

    watch(
      () =>
        [
          props.modelValue,
          props.focusKey,
          props.baseUrlMode,
          props.showBaseUrl,
          props.showApiKey,
        ] as const,
      ([open, focusKey, _baseUrlMode, _showBaseUrl, showApiKey]) => {
        const baseUrlMode = resolveBaseUrlMode()
        if (!open) {
          focusedField.value = null
          return
        }
        if (focusKey && showApiKey) {
          focusedField.value = 'apiKey'
          return
        }
        if (baseUrlMode === 'editable') {
          focusedField.value = 'baseUrl'
          return
        }
        focusedField.value = showApiKey ? 'apiKey' : null
      },
      { immediate: true },
    )

    return () => {
      if (!props.modelValue)
        return null

      const dialogW = Math.max(44, Math.floor(props.w))
      const dialogH = Math.max(12, Math.floor(props.h))
      const innerW = Math.max(0, dialogW - 4)
      const innerH = Math.max(0, dialogH - 4)
      const contentH = Math.max(0, innerH - 1)

      const dialogBg = ui.token('dialog.chrome')?.bg
      const dialogBgStyle = dialogBg ? { bg: dialogBg } : undefined
      const hintStyle = ui.style(['dialog.chrome', 'text.muted'])
      const boxStyle = ui.style(['dialog.chrome', 'border.default'])
      const fieldStyle = ui.style(['input.field'], dialogBgStyle)
      const baseUrlMode = resolveBaseUrlMode()
      const showBaseUrl = baseUrlMode !== 'hidden'
      const editableBaseUrl = baseUrlMode === 'editable'

      const fieldBoxH = contentH >= 7 ? 4 : 3
      const inputH = Math.max(1, fieldBoxH - 2)
      const minRowsForFields
        = (showBaseUrl ? fieldBoxH : 0) + (props.showApiKey ? fieldBoxH : 0)
      const statusLines = props.applying
        ? wrapByCells(
            t('providerConnectDialog.applyingHint'),
            Math.max(1, innerW),
          ).slice(0, 1)
        : []
      const statusH = statusLines.length
      const maxHintRowsBySpace = Math.max(
        0,
        contentH - minRowsForFields - statusH,
      )
      const hintMaxLines = Math.min(2, maxHintRowsBySpace)
      const hintText = t('providerConnectDialog.hintGeneric')
      const hintLines
        = hintMaxLines > 0
          ? wrapByCells(hintText, Math.max(1, innerW)).slice(0, hintMaxLines)
          : []
      const hintH = hintLines.length
      const showHint = hintH > 0
      const hintValue = hintLines.join('\n')
      const statusY = hintH
      const statusValue = statusLines.join('\n')
      const statusStyle = ui.style(['dialog.chrome', 'text.muted'])
      const clearLabel = t('providerConnectDialog.clearKey')

      const topHintNode = showHint
        ? h(TText, {
            x: 0,
            y: 0,
            w: innerW,
            h: hintH,
            wrap: true,
            value: hintValue,
            style: hintStyle,
          })
        : null

      let y = hintH + statusH
      const currentLineH = 1
      const wantCurrentLine = props.showApiKey && Boolean(props.apiKeyMasked)
      let canShowCurrentLine = false
      let apiKeyHintY = 0
      let apiKeyY = 0
      let baseUrlY = 0

      if (props.baseUrlAfterApiKey) {
        apiKeyHintY = y
        canShowCurrentLine
          = wantCurrentLine && y + currentLineH + fieldBoxH <= contentH
        if (canShowCurrentLine)
          y += currentLineH
        apiKeyY = y
        if (props.showApiKey)
          y += fieldBoxH
        baseUrlY = y
        if (showBaseUrl)
          y += fieldBoxH
      }
      else {
        baseUrlY = y
        if (showBaseUrl)
          y += fieldBoxH
        apiKeyHintY = y
        canShowCurrentLine
          = wantCurrentLine && y + currentLineH + fieldBoxH <= contentH
        if (canShowCurrentLine)
          y += currentLineH
        apiKeyY = y
        if (props.showApiKey)
          y += fieldBoxH
      }

      const applyLabel = props.applying
        ? t('providerConnectDialog.applyingButton')
        : t('common.apply')

      return h(
        TDialog as any,
        {
          'modelValue': props.modelValue,
          'onUpdate:modelValue': (v: boolean) => emit('update:modelValue', v),
          'onKeydownCapture': (e: any) => {
            if (e?.key === 'Escape') {
              ;(e as any).__tuiDialogClose = true
            }
          },
          'w': dialogW,
          'h': dialogH,
          'title': t('providerConnectDialog.title', {
            provider:
              props.providerName || t('providerConnectDialog.providerFallback'),
          }),
          'placement': 'center',
          'backdrop': props.backdrop,
          'closeOnBackdrop': false,
          'padding': 1,
          'style': ui.style(['dialog.chrome']),
          'buttons': [
            {
              label: applyLabel,
              value: 'apply',
              kind: 'primary',
            },
            ...(props.canClearKey
              ? [{ label: clearLabel, value: 'clear', kind: 'danger' as const }]
              : []),
            { label: t('common.cancel'), value: 'cancel' },
          ],
          'closeOnConfirm': false,
          'onConfirm': (btn: any) => {
            if (btn?.value === 'apply') {
              if (props.applying)
                return
              emit('apply')
            }
            else if (btn?.value === 'clear') {
              if (props.applying)
                return
              emit('clearKey')
            }
            else {
              emit('cancel')
            }
          },
          'onClose': () => emit('cancel'),
        },
        () => [
          topHintNode,
          statusH > 0
            ? h(TText, {
                x: 0,
                y: statusY,
                w: innerW,
                h: statusH,
                value: statusValue,
                style: statusStyle,
                wrap: true,
              })
            : null,
          showBaseUrl
            ? h(
                TBox,
                {
                  x: 0,
                  y: baseUrlY,
                  w: innerW,
                  h: fieldBoxH,
                  border: true,
                  title: editableBaseUrl
                    ? withFocusedInputTip(
                        t('providerConnectDialog.baseUrlTitle'),
                        focusedField.value === 'baseUrl',
                        t('common.inputClearTip'),
                      )
                    : t('providerConnectDialog.baseUrlTitle'),
                  padding: 0,
                  style: boxStyle,
                  clear: true,
                },
                () =>
                  editableBaseUrl
                    ? h(TInput, {
                        'x': 0,
                        'y': 0,
                        'w': Math.max(0, innerW - 2),
                        'h': inputH,
                        'modelValue': props.baseUrl,
                        'onUpdate:modelValue': (v: string) =>
                          emit('update:baseUrl', v),
                        'placeholder': t(
                          'providerConnectDialog.baseUrlPlaceholder',
                        ),
                        'cursorToEndOnFirstFocus': true,
                        'cursorToEndOnExternalUpdate': true,
                        'style': fieldStyle,
                        'zIndex': 1002,
                        'autoFocus': !props.focusKey,
                        'onFocus': () => {
                          focusedField.value = 'baseUrl'
                        },
                        'onBlur': () => {
                          focusedField.value = null
                        },
                      })
                    : h(TText, {
                        x: 0,
                        y: 0,
                        w: Math.max(0, innerW - 2),
                        h: inputH,
                        value:
                          props.baseUrl
                          || t('providerConnectDialog.baseUrlPlaceholder'),
                        style: fieldStyle,
                        wrap: true,
                      }),
              )
            : null,

          props.showApiKey && canShowCurrentLine
            ? h(TText, {
                x: 0,
                y: apiKeyHintY,
                w: innerW,
                value: props.apiKeyMasked
                  ? t('providerConnectDialog.apiKeyCurrent', {
                      value: props.apiKeyMasked,
                    })
                  : t('providerConnectDialog.apiKeyNotSet'),
                style: hintStyle,
              })
            : null,

          props.showApiKey
            ? h(
                TBox,
                {
                  x: 0,
                  y: apiKeyY,
                  w: innerW,
                  h: fieldBoxH,
                  border: true,
                  title: withFocusedInputTip(
                    t('providerConnectDialog.apiKeyTitle'),
                    focusedField.value === 'apiKey',
                    t('common.inputClearTip'),
                  ),
                  padding: 0,
                  style: boxStyle,
                  clear: true,
                },
                () =>
                  h(TInput, {
                    'x': 0,
                    'y': 0,
                    'w': Math.max(0, innerW - 2),
                    'h': inputH,
                    'modelValue': props.apiKeyDraft,
                    'onUpdate:modelValue': (v: string) =>
                      emit('update:apiKeyDraft', v),
                    'placeholder': t('providerConnectDialog.apiKeyPlaceholder'),
                    'secret': true,
                    'cursorToEndOnFirstFocus': true,
                    'cursorToEndOnExternalUpdate': true,
                    'style': fieldStyle,
                    'zIndex': 1002,
                    'autoFocus': props.focusKey,
                    'onFocus': () => {
                      focusedField.value = 'apiKey'
                    },
                    'onBlur': () => {
                      focusedField.value = null
                    },
                  }),
              )
            : null,
        ],
      )
    }
  },
})
