<template>
  <a-modal
    :visible="visible"
    :title="modalTitle"
    :width="940"
    :mask-closable="false"
    :confirm-loading="submitLoading"
    :ok-text="okText"
    :cancel-text="'取消'"
    :ok-button-props="{ disabled: blockedNoIdentity || loading }"
    unmount-on-close
    @ok="handleSubmit"
    @cancel="handleCancel"
  >
    <div class="modal-scroll">
      <a-spin :loading="loading" style="width: 98%; margin: 0 auto; min-height: 200px">
        <div v-if="!loading && blockedNoIdentity" class="blocked-wrap">
          <a-alert type="warning" show-icon>
            当前服务器未配置唯一标识。请先在「编辑服务器」中填写并保存，以便与 DC-Hardware 带外设备关联。
          </a-alert>
        </div>

        <template v-else-if="!loading">
          <a-form ref="formRef" :model="form" :rules="rules" layout="vertical">
            <a-divider orientation="left">基础信息</a-divider>
            <a-row :gutter="16">
              <a-col :span="12">
                <a-form-item label="管理 IP（BMC / 带外）">
                  <span class="readonly-field">{{ managementIp || '—' }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="12">
                <a-form-item field="collect_interval" label="采集间隔（秒）">
                  <a-input-number v-model="form.collect_interval" :min="0" style="width: 100%" />
                  <template #extra>
                    <span class="form-extra">0 或留空表示使用服务默认间隔</span>
                  </template>
                </a-form-item>
              </a-col>
              <a-col :span="12">
                <a-form-item label="启用监控">
                  <a-switch v-model="form.enabled" />
                </a-form-item>
              </a-col>
              <a-col :span="12">
                <a-form-item field="tags" label="标签">
                  <a-input v-model="form.tags" placeholder="可为 JSON 字符串，如实体传感器配置等" allow-clear />
                </a-form-item>
              </a-col>
              <a-col :span="24">
                <a-form-item field="extra_config" label="扩展配置（JSON 字符串）">
                  <a-textarea v-model="form.extra_config" :rows="4" placeholder='可选，非空须为合法 JSON，如 {"key":"value"}' allow-clear />
                </a-form-item>
              </a-col>
            </a-row>

            <a-divider orientation="left">采集协议与连接</a-divider>
            <a-form-item field="protocol" label="协议" required>
              <a-radio-group :model-value="form.protocol" type="button" @update:model-value="onProtocolModelUpdate">
                <a-radio value="ipmi">IPMI</a-radio>
                <a-radio value="snmp">SNMP</a-radio>
                <a-radio value="redfish">Redfish</a-radio>
              </a-radio-group>
              <template #extra>
                <span class="form-extra">切换协议后请填写对应区域的认证与端口；默认值：IPMI 623、SNMP 161</span>
              </template>
            </a-form-item>

            <template v-if="form.protocol === 'ipmi' || form.protocol === 'redfish'">
              <a-row :gutter="16">
                <a-col :span="12">
                  <a-form-item field="username" label="用户名">
                    <a-input v-model="form.username" placeholder="BMC 用户名" allow-clear />
                  </a-form-item>
                </a-col>
                <a-col :span="12">
                  <a-form-item field="password" label="密码">
                    <a-input-password v-model="form.password" :placeholder="passwordPlaceholder" allow-clear />
                    <template #extra>
                      <span class="form-extra">{{ passwordHint }}</span>
                    </template>
                  </a-form-item>
                </a-col>
              </a-row>
            </template>

            <template v-if="form.protocol === 'ipmi'">
              <a-row :gutter="16">
                <a-col :span="8">
                  <a-form-item field="port" label="IPMI 端口">
                    <a-input-number v-model="form.port" :min="1" :max="65535" style="width: 100%" />
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item field="ipmi_timeout_seconds" label="超时（秒）">
                    <a-input-number v-model="form.ipmi_timeout_seconds" :min="0" style="width: 100%" />
                    <template #extra><span class="form-extra">0 表示使用服务默认</span></template>
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item label="启用 IPMI 采集">
                    <a-switch v-model="form.ipmi_collect_enabled" />
                  </a-form-item>
                </a-col>
              </a-row>
            </template>

            <template v-if="form.protocol === 'snmp'">
              <a-row :gutter="16">
                <a-col :span="8">
                  <a-form-item field="snmp_port" label="SNMP 端口">
                    <a-input-number v-model="form.snmp_port" :min="1" :max="65535" style="width: 100%" />
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item field="snmp_version" label="SNMP 版本">
                    <a-select v-model="form.snmp_version" allow-clear>
                      <a-option value="v2c">v2c</a-option>
                      <a-option value="v1">v1</a-option>
                    </a-select>
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item field="snmp_timeout_seconds" label="超时（秒）">
                    <a-input-number v-model="form.snmp_timeout_seconds" :min="0" style="width: 100%" />
                  </a-form-item>
                </a-col>
                <a-col :span="12">
                  <a-form-item field="community" label="Community 共享口令">
                    <a-input v-model="form.community" placeholder="v2c Community" allow-clear />
                  </a-form-item>
                </a-col>
                <a-col :span="12">
                  <a-form-item label="启用 SNMP 采集">
                    <a-switch v-model="form.snmp_collect_enabled" />
                  </a-form-item>
                </a-col>
              </a-row>
              <SnmpOidEditor
                ref="snmpOidEditorRef"
                v-model="form.snmp_oids"
                :reset-key="snmpOidEditorResetKey"
              />
            </template>

            <template v-if="form.protocol === 'redfish'">
              <a-row :gutter="16">
                <a-col :span="24">
                  <a-form-item field="redfish_base_url" label="Redfish 根 URL">
                    <a-input v-model="form.redfish_base_url" placeholder="留空则默认 https://{管理IP}/redfish/v1" allow-clear />
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item label="跳过 TLS 校验">
                    <a-switch v-model="form.redfish_tls_skip_verify" />
                    <template #extra><span class="form-extra">仅内网测试环境建议开启</span></template>
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item field="redfish_timeout_seconds" label="超时（秒）">
                    <a-input-number v-model="form.redfish_timeout_seconds" :min="0" style="width: 100%" />
                  </a-form-item>
                </a-col>
                <a-col :span="8">
                  <a-form-item label="启用 Redfish 采集">
                    <a-switch v-model="form.redfish_collect_enabled" />
                  </a-form-item>
                </a-col>
              </a-row>
            </template>

            <a-divider orientation="left">备注</a-divider>
            <a-row :gutter="16">
              <a-col :span="24">
                <a-form-item field="description" label="备注">
                  <a-textarea v-model="form.description" :rows="2" placeholder="可选" allow-clear />
                </a-form-item>
              </a-col>
            </a-row>
          </a-form>
        </template>
      </a-spin>
    </div>
  </a-modal>
</template>

<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { FormInstance, FieldRule } from '@arco-design/web-vue'
import type { ServerItem } from '@/api/ops/server'
import {
  fetchHostHardwareLatestCollection,
  fetchHostHardwareDevice,
  fetchHostHardwareDeviceList,
  createHostHardwareDevice,
  updateHostHardwareDevice,
  isHostHardwareApiSuccess,
  unwrapHostHardwareDetails,
  type HostHardwareDevice,
  type HostHardwareDeviceUpsert,
} from '@/api/ops/host-hardware'
import SnmpOidEditor from '../../components/SnmpOidEditor.vue'

interface Props {
  visible: boolean
  record: ServerItem | null
}

const props = defineProps<Props>()
const emit = defineEmits(['update:visible', 'success'])

const formRef = ref<FormInstance>()
const snmpOidEditorRef = ref<InstanceType<typeof SnmpOidEditor>>()
const snmpOidEditorResetKey = ref(0)
const loading = ref(false)
const submitLoading = ref(false)
const blockedNoIdentity = ref(false)
const deviceId = ref<string | null>(null)

/** 防止多次触发 loadHardware 时，较早返回的请求覆盖用户已切换的协议/表单 */
let hardwareLoadGeneration = 0

function onProtocolModelUpdate(v: 'ipmi' | 'snmp' | 'redfish') {
  form.protocol = v
}

const isEdit = computed(() => !!deviceId.value)

/** 已存在 DC-Hardware 设备时为「修改」，否则为「新增」 */
const modalTitle = computed(() => {
  if (loading.value) return '硬件设备配置'
  if (blockedNoIdentity.value) return '硬件设备配置'
  return deviceId.value ? '修改硬件设备配置' : '新增硬件设备配置'
})

const okText = computed(() => {
  if (loading.value || blockedNoIdentity.value) return '保存'
  return deviceId.value ? '保存修改' : '保存'
})

/** 与列表行一致：ip_address 优先，否则 host（同服务器管理列表） */
const managementIp = computed(() => {
  const r = props.record
  if (!r) return ''
  return (r.ip_address || r.host || '').trim()
})

/** 与接口对齐：名称/位置/关联键来自服务器档案；类型与资产 ID 在编辑时来自已加载设备 */
const hardwareType = ref('server')
const hardwareAssetId = ref('')

const passwordPlaceholder = computed(() => (isEdit.value ? '留空则不修改已保存的密码' : 'BMC / Redfish 密码'))

const passwordHint = computed(() => (isEdit.value ? '编辑时留空将保留原密码' : '按机房安全要求妥善保管'))

const form = reactive({
  protocol: 'ipmi' as 'ipmi' | 'snmp' | 'redfish',
  username: '',
  password: '',
  port: 623,
  snmp_port: 161,
  community: '',
  snmp_version: 'v2c',
  snmp_oids: '',
  redfish_base_url: '',
  redfish_tls_skip_verify: false,
  description: '',
  tags: '',
  extra_config: '',
  ipmi_timeout_seconds: 0,
  snmp_timeout_seconds: 0,
  redfish_timeout_seconds: 0,
  ipmi_collect_enabled: true,
  snmp_collect_enabled: true,
  redfish_collect_enabled: true,
  collect_interval: 0,
  enabled: true,
})

const rules: Record<string, FieldRule | FieldRule[]> = {
  protocol: [{ required: true, message: '请选择协议' }],
}

function resetForm() {
  hardwareType.value = 'server'
  hardwareAssetId.value = ''
  form.protocol = 'ipmi'
  form.username = ''
  form.password = ''
  form.port = 623
  form.snmp_port = 161
  form.community = ''
  form.snmp_version = 'v2c'
  form.snmp_oids = ''
  form.redfish_base_url = ''
  form.redfish_tls_skip_verify = false
  form.description = ''
  form.tags = ''
  form.extra_config = ''
  form.ipmi_timeout_seconds = 0
  form.snmp_timeout_seconds = 0
  form.redfish_timeout_seconds = 0
  form.ipmi_collect_enabled = true
  form.snmp_collect_enabled = true
  form.redfish_collect_enabled = true
  form.collect_interval = 0
  form.enabled = true
  snmpOidEditorResetKey.value += 1
}

function applyFromServer(r: ServerItem) {
  resetForm()
  form.description = r.description || ''
  form.tags = r.tags || ''
}

function applyFromDevice(d: HostHardwareDevice) {
  resetForm()
  hardwareType.value = (d.type || 'server').trim() || 'server'
  hardwareAssetId.value = (d.asset_id || '').trim()
  form.protocol = (d.protocol as typeof form.protocol) || 'ipmi'
  form.username = d.username || ''
  form.password = ''
  form.port = d.port ?? 623
  form.snmp_port = d.snmp_port ?? 161
  form.community = d.community || ''
  form.snmp_version = d.snmp_version || 'v2c'
  form.snmp_oids = d.snmp_oids || ''
  form.redfish_base_url = d.redfish_base_url || ''
  form.redfish_tls_skip_verify = !!d.redfish_tls_skip_verify
  form.description = d.description || ''
  form.tags = d.tags || ''
  form.extra_config = d.extra_config || ''
  form.ipmi_timeout_seconds = d.ipmi_timeout_seconds ?? 0
  form.snmp_timeout_seconds = d.snmp_timeout_seconds ?? 0
  form.redfish_timeout_seconds = d.redfish_timeout_seconds ?? 0
  form.ipmi_collect_enabled = d.ipmi_collect_enabled !== false
  form.snmp_collect_enabled = d.snmp_collect_enabled !== false
  form.redfish_collect_enabled = d.redfish_collect_enabled !== false
  form.collect_interval = d.collect_interval ?? 0
  form.enabled = d.enabled !== false
  snmpOidEditorResetKey.value += 1
}

function validateExtraConfigJson(): boolean {
  const s = form.extra_config?.trim()
  if (!s) return true
  try {
    JSON.parse(s)
    return true
  } catch {
    Message.error('扩展配置须为合法 JSON')
    return false
  }
}

function buildPayload(): HostHardwareDeviceUpsert {
  const r = props.record
  const name = (r?.name || '').trim()
  const serverIdentity = (r?.server_identity || '').trim()
  const location = (r?.location || '').trim()
  const p: HostHardwareDeviceUpsert = {
    name,
    ip: managementIp.value,
    type: (hardwareType.value || 'server').trim() || 'server',
    protocol: form.protocol,
    username: form.username?.trim() || undefined,
    port: form.port,
    snmp_port: form.snmp_port,
    community: form.community?.trim() || undefined,
    snmp_version: form.snmp_version?.trim() || undefined,
    snmp_oids: form.protocol === 'snmp' ? form.snmp_oids?.trim() || '[]' : '[]',
    redfish_base_url: form.redfish_base_url?.trim() || undefined,
    redfish_tls_skip_verify: form.redfish_tls_skip_verify,
    location: location || undefined,
    description: form.description?.trim() || undefined,
    tags: form.tags?.trim() || undefined,
    asset_id: hardwareAssetId.value?.trim() || undefined,
    server_identity: serverIdentity || undefined,
    extra_config: form.extra_config?.trim() || undefined,
    ipmi_timeout_seconds: form.ipmi_timeout_seconds,
    snmp_timeout_seconds: form.snmp_timeout_seconds,
    redfish_timeout_seconds: form.redfish_timeout_seconds,
    ipmi_collect_enabled: form.ipmi_collect_enabled,
    snmp_collect_enabled: form.snmp_collect_enabled,
    redfish_collect_enabled: form.redfish_collect_enabled,
    collect_interval: form.collect_interval,
    enabled: form.enabled,
  }
  const pw = form.password?.trim()
  if (pw) {
    p.password = pw
  }
  return p
}

/** 按设备 id 拉详情并写入表单（gen 用于丢弃过期请求，避免覆盖用户已改的协议） */
async function loadDeviceDetailIntoForm(id: string, gen: number): Promise<boolean> {
  const devRes = await fetchHostHardwareDevice(id)
  if (gen !== hardwareLoadGeneration) return false
  if (!isHostHardwareApiSuccess(devRes)) return false
  const detail = unwrapHostHardwareDetails(devRes)
  const dev = detail?.device
  if (!dev?.id) return false
  if (gen !== hardwareLoadGeneration) return false
  deviceId.value = dev.id
  applyFromDevice(dev)
  return true
}

/** collection 接口失败或缺 device_id 时，按 server_identity 在列表中查找设备再拉详情 */
async function loadDeviceByServerIdentityFallback(sid: string, gen: number): Promise<boolean> {
  const listRes = await fetchHostHardwareDeviceList({ page: 1, page_size: 500 })
  if (gen !== hardwareLoadGeneration) return false
  if (!isHostHardwareApiSuccess(listRes)) return false
  const payload = unwrapHostHardwareDetails(listRes)
  const rows = payload?.data ?? []
  const found = rows.find((d) => (d.server_identity || '').trim() === sid)
  if (!found?.id) return false
  return loadDeviceDetailIntoForm(found.id, gen)
}

async function loadHardware() {
  const gen = ++hardwareLoadGeneration
  deviceId.value = null
  blockedNoIdentity.value = false
  if (!props.record) {
    return
  }
  const sid = (props.record.server_identity || '').trim()
  if (!sid) {
    blockedNoIdentity.value = true
    if (gen !== hardwareLoadGeneration) return
    applyFromServer(props.record)
    return
  }

  loading.value = true
  try {
    const colRes = await fetchHostHardwareLatestCollection(sid)
    if (gen !== hardwareLoadGeneration) return
    if (isHostHardwareApiSuccess(colRes)) {
      const col = unwrapHostHardwareDetails(colRes)
      const did = col?.device_id
      deviceId.value = did ?? null
      if (did) {
        const detailOk = await loadDeviceDetailIntoForm(did, gen)
        if (gen !== hardwareLoadGeneration) return
        if (detailOk) return
      }
    }
    if (gen !== hardwareLoadGeneration) return
    if (await loadDeviceByServerIdentityFallback(sid, gen)) {
      if (gen !== hardwareLoadGeneration) return
      return
    }
    if (gen !== hardwareLoadGeneration) return
    applyFromServer(props.record)
  } catch {
    if (gen !== hardwareLoadGeneration) return
    if (await loadDeviceByServerIdentityFallback(sid, gen)) {
      if (gen !== hardwareLoadGeneration) return
      return
    }
    if (gen !== hardwareLoadGeneration) return
    applyFromServer(props.record)
  } finally {
    if (gen === hardwareLoadGeneration) {
      loading.value = false
    }
  }
}

watch(
  () => props.visible,
  (visible) => {
    if (visible && props.record) {
      formRef.value?.clearValidate()
      loadHardware()
    }
    if (!visible) {
      hardwareLoadGeneration += 1
      loading.value = false
      resetForm()
      deviceId.value = null
      blockedNoIdentity.value = false
    }
  }
)

async function handleSubmit() {
  if (blockedNoIdentity.value) {
    Message.warning('请先在编辑服务器中配置唯一标识')
    return
  }
  const validateErrors = await formRef.value?.validate()
  if (validateErrors) {
    return
  }
  if (!validateExtraConfigJson()) return
  if (form.protocol === 'snmp' && !snmpOidEditorRef.value?.validate()) {
    return
  }

  const r = props.record
  console.log('r,', r)
  if (!(r?.name || '').trim()) {
    Message.error('服务器名称为空，请先在编辑服务器中填写名称')
    return
  }
  if (!managementIp.value) {
    Message.error('当前服务器未配置 IP 或主机地址，请先在编辑服务器中维护后再保存硬件配置')
    return
  }

  submitLoading.value = true
  console.log('deviceId.value,', deviceId.value)
  try {
    const payload = buildPayload()
    let res: { code?: number | string; message?: string }
    if (deviceId.value) {
      res = (await updateHostHardwareDevice(deviceId.value, payload)) as typeof res
    } else {
      res = (await createHostHardwareDevice(payload)) as typeof res
    }
    if (isHostHardwareApiSuccess(res)) {
      Message.success(deviceId.value ? '修改成功' : '保存成功')
      emit('success')
      emit('update:visible', false)
    } else {
      Message.error((res as { message?: string }).message || '保存失败')
    }
  } catch (e: unknown) {
    const msg =
      (e as { response?: { data?: { message?: string } }; message?: string })?.response?.data?.message ||
      (e as { message?: string })?.message
    Message.error(msg || '保存失败')
  } finally {
    submitLoading.value = false
  }
}

function handleCancel() {
  emit('update:visible', false)
}
</script>

<script lang="ts">
export default {
  name: 'HardwareDeviceConfigDialog',
}
</script>

<style scoped lang="less">
.form-extra {
  color: var(--color-text-3);
  font-size: 12px;
}

.blocked-wrap {
  padding: 8px 0;
}

.readonly-field {
  color: var(--color-text-1);
  font-weight: 500;
}

.modal-scroll {
  max-height: min(72vh, 720px);
  overflow-y: auto;
}
</style>
