<template>
  <ElCard shadow="never" class="info-card operation-logs-card" v-loading="loading">
    <template #header>
      <div class="card-header">
        <span class="header-title">操作审计日志</span>
        <div class="filter-section">
          <ElSelect
            v-model="filterForm.operation_type"
            placeholder="操作类型"
            clearable
            class="operation-type-select"
            @change="handleFilterChange"
          >
            <ElOption
              v-for="option in operationTypeOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </ElSelect>
          <ElSelect
            v-model="filterForm.result_status"
            placeholder="执行结果"
            clearable
            class="result-status-select"
            @change="handleFilterChange"
          >
            <ElOption label="成功" value="success" />
            <ElOption label="失败" value="failed" />
            <ElOption label="拒绝" value="denied" />
          </ElSelect>
          <ElButton type="primary" @click="handleQuery">查询</ElButton>
          <ElButton @click="handleReset">重置</ElButton>
          <ElTag type="info" size="small">共 {{ total }} 条</ElTag>
        </div>
      </div>
    </template>

    <div class="logs-table-wrapper">
      <ElTable :data="logList" class="logs-table" border max-height="400">
        <ElTableColumn label="操作时间" width="170" align="center">
          <template #default="{ row }">
            {{ formatDateTime(row.created_at) }}
          </template>
        </ElTableColumn>
        <ElTableColumn label="操作类型" width="160" align="center">
          <template #default="{ row }">
            <ElTag :type="getOperationTypeTag(row.operation_type)" size="small">
              {{ row.operation_desc }}
            </ElTag>
          </template>
        </ElTableColumn>
        <ElTableColumn label="操作人" width="130" align="center">
          <template #default="{ row }">
            {{ row.operator_name || '-' }}
          </template>
        </ElTableColumn>
        <ElTableColumn label="操作人类型" width="110" align="center">
          <template #default="{ row }">
            {{ getOperatorTypeText(row) }}
          </template>
        </ElTableColumn>
        <ElTableColumn label="执行结果" width="100" align="center">
          <template #default="{ row }">
            <ElTag :type="getResultStatusTag(row.result_status)" size="small">
              {{ getResultStatusText(row.result_status) }}
            </ElTag>
          </template>
        </ElTableColumn>
        <ElTableColumn label="变更内容" min-width="320">
          <template #default="{ row }">
            <div v-if="getDisplayContent(row).length" class="change-content">
              <span
                v-for="(item, index) in getDisplayContent(row)"
                :key="`${item.type}-${item.key}-${index}`"
                class="change-item"
              >
                <span class="field-name">{{ item.fieldName }}</span>
                <span class="field-value">
                  <template v-if="item.type === 'change'">
                    <span class="new-value">{{ formatFieldValue(item.key, item.afterValue) }}</span>
                    <ElButton
                      v-if="canDownloadLogFile && isDownloadableFileKey(item.key, item.afterValue)"
                      link
                      type="primary"
                      @click.stop="handleDownloadLogFile(item.afterValue)"
                    >
                      下载文件
                    </ElButton>
                  </template>
                  <span v-else :class="['message-value', item.level === 'error' ? 'is-error' : '']">
                    {{ item.message }}
                  </span>
                </span>
              </span>
            </div>
            <span v-else>-</span>
          </template>
        </ElTableColumn>
      </ElTable>
      <ElPagination
        class="logs-pagination"
        v-if="total > 0"
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.page_size"
        :total="total"
        :page-sizes="[10, 20, 50]"
        layout="total, prev, pager, next"
        @current-change="handlePageChange"
        @size-change="handleSizeChange"
      />
    </div>
  </ElCard>
</template>

<script setup lang="ts">
  import { computed, reactive, ref, watch } from 'vue'
  import {
    ElButton,
    ElCard,
    ElMessage,
    ElOption,
    ElPagination,
    ElSelect,
    ElTable,
    ElTableColumn,
    ElTag
  } from 'element-plus'
  import { AssetService, StorageService } from '@/api/modules'
  import { useAuth } from '@/composables/useAuth'
  import type { AssetOperationLogItem } from '@/types/api'
  import { formatDateTime } from '@/utils/business/format'

  interface Props {
    assetIdentifier?: string
    assetType?: string
    downloadPermission?: string
  }

  type TagType = 'primary' | 'success' | 'warning' | 'info' | 'danger'
  type ResultStatus = '' | 'success' | 'failed' | 'denied'

  type OperationLogRow = AssetOperationLogItem & {
    operator_type_code?: string
    error_code?: string
    error_msg?: string
    request_id?: string
    request_path?: string
    request_method?: string
    ip_address?: string
    user_agent?: string
  }

  interface ChangeItem {
    type: 'change'
    key: string
    fieldName: string
    beforeValue?: any
    afterValue?: any
  }

  interface MessageItem {
    type: 'message'
    key: string
    fieldName: string
    message: string
    level: 'info' | 'error'
  }

  type DisplayItem = ChangeItem | MessageItem

  const operationTypeOptions = [
    { label: '设备WiFi设置', value: 'device_set_wifi' },
    { label: '设备切卡', value: 'device_switch_card' },
    { label: '设备切卡模式', value: 'device_switch_mode' },
    { label: '设备停机', value: 'device_stop' },
    { label: '设备复机', value: 'device_start' },
    { label: '设备重启', value: 'device_reboot' },
    { label: '设备重置', value: 'device_reset' },
    { label: '设备分配', value: 'device_allocate' },
    { label: '设备回收', value: 'device_recall' },
    { label: '设备绑卡', value: 'device_bind_card' },
    { label: '设备解绑卡', value: 'device_unbind_card' },
    { label: '卡分配', value: 'card_allocate' },
    { label: '卡回收', value: 'card_recall' },
    { label: '卡停机', value: 'card_stop' },
    { label: '卡复机', value: 'card_start' },
    { label: '手动停卡', value: 'card_manual_stop' },
    { label: '手动复机', value: 'card_manual_start' },
    { label: '自动停卡', value: 'card_auto_stop' },
    { label: '自动复机', value: 'card_auto_start' },
    { label: '卡轮询状态', value: 'card_polling_status' },
    { label: '资产轮询状态', value: 'asset_polling_status' },
    { label: '实名策略', value: 'asset_realname_policy' },
    { label: '实名状态', value: 'asset_realname_status' },
    { label: '轮询开关', value: 'asset_polling' },
    { label: 'IoT卡导入任务', value: 'iot_card_import_task_create' }
  ] as const

  const operationTypeTagMap: Record<string, TagType> = {
    device_set_wifi: 'primary',
    device_switch_card: 'success',
    device_switch_mode: 'success',
    device_stop: 'danger',
    device_start: 'success',
    device_reboot: 'warning',
    device_reset: 'warning',
    device_allocate: 'primary',
    device_recall: 'warning',
    device_bind_card: 'primary',
    device_unbind_card: 'warning',
    card_allocate: 'primary',
    card_recall: 'warning',
    card_stop: 'danger',
    card_start: 'success',
    card_manual_stop: 'danger',
    card_manual_start: 'success',
    card_auto_stop: 'danger',
    card_auto_start: 'success',
    card_polling_status: 'info',
    asset_realname_policy: 'info',
    asset_realname_status: 'info',
    asset_polling: 'info',
    asset_polling_status: 'info',
    iot_card_import_task_create: 'primary'
  }

  const operatorTypeMap: Record<string, string> = {
    system: '系统',
    admin_user: '平台用户',
    agent_user: '代理账号',
    enterprise_user: '企业用户',
    api_user: 'API用户'
  }

  const fieldNameMap: Record<string, string> = {
    asset_type: '资产类型',
    batch_no: '批次号',
    card_category: '卡类型',
    device_imei: '设备IMEI',
    device_sn: '设备SN',
    device_virtual_no: '设备虚拟号',
    device_virtual_nos: '设备虚拟号',
    enable_polling: '轮询开关',
    file_key: '文件存储键',
    first_realname_at: '首次实名时间',
    iccid: 'ICCID',
    iccids: 'ICCID',
    network_status: '网络状态',
    real_name_status: '实名状态',
    realname_policy: '实名认证策略',
    shop_name: '店铺',
    source_service: '来源服务',
    source_shop_name: '来源店铺',
    status: '资产状态',
    stop_reason: '停机原因',
    switch_mode: '切卡模式',
    target_shop_name: '目标店铺',
    to_shop_name: '目标店铺'
  }

  const realnamePolicyMap: Record<string, string> = {
    none: '无需实名',
    before_order: '先实名后充值/购买',
    after_order: '先充值/购买后实名'
  }

  const stopReasonMap: Record<string, string> = {
    '': '无',
    no_package: '无可用套餐',
    carrier_stopped: '运营商停机',
    not_realname: '未实名'
  }

  const assetTypeMap: Record<string, string> = {
    iot_card: 'IoT卡',
    device: '设备'
  }

  const cardCategoryMap: Record<string, string> = {
    normal: '普通卡',
    industry: '行业卡'
  }

  const assetStatusMap: Record<string, string> = {
    '1': '在库',
    '2': '已分销',
    '3': '已激活',
    '4': '已停用'
  }

  const newStatusMap: Record<string, string> = {
    allocated: '已分配',
    recalled: '已回收'
  }

  const props = defineProps<Props>()
  const { hasAuth } = useAuth()

  const loading = ref(false)
  const logList = ref<OperationLogRow[]>([])
  const total = ref(0)
  const canDownloadLogFile = computed(() => {
    return props.downloadPermission ? hasAuth(props.downloadPermission) : false
  })
  const pagination = reactive({
    page: 1,
    page_size: 20
  })

  const filterForm = reactive({
    operation_type: '',
    result_status: '' as ResultStatus
  })

  const loadLogs = async () => {
    if (!props.assetIdentifier) return

    try {
      loading.value = true
      const res = await AssetService.getOperationLogs(props.assetIdentifier, {
        page: pagination.page,
        page_size: pagination.page_size,
        operation_type: filterForm.operation_type || undefined,
        result_status: filterForm.result_status || undefined
      })
      if (res.code === 0 && res.data) {
        logList.value = res.data.items || []
        total.value = res.data.total || 0
      }
    } catch (error) {
      console.error('加载操作日志失败:', error)
      ElMessage.error('加载操作日志失败')
    } finally {
      loading.value = false
    }
  }

  const handleQuery = () => {
    pagination.page = 1
    loadLogs()
  }

  const handleReset = () => {
    filterForm.operation_type = ''
    filterForm.result_status = ''
    pagination.page = 1
    loadLogs()
  }

  const handleFilterChange = () => {
    handleQuery()
  }

  const handlePageChange = () => {
    loadLogs()
  }

  const handleSizeChange = () => {
    pagination.page = 1
    loadLogs()
  }

  const getOperationTypeTag = (type: string): TagType => {
    return operationTypeTagMap[type] || 'info'
  }

  const getResultStatusTag = (status: string): TagType => {
    const tagMap: Record<string, TagType> = {
      success: 'success',
      failed: 'danger',
      denied: 'warning'
    }
    return tagMap[status] || 'info'
  }

  const getResultStatusText = (status: string) => {
    const textMap: Record<string, string> = {
      success: '成功',
      failed: '失败',
      denied: '拒绝'
    }
    return textMap[status] || status
  }

  const isDownloadableFileKey = (key: string, value: unknown) => {
    return key === 'file_key' && typeof value === 'string' && value.trim() !== ''
  }

  const handleDownloadLogFile = async (fileKey: string) => {
    try {
      await StorageService.downloadFileByKey(fileKey)
      ElMessage.success('文件下载已开始')
    } catch (error) {
      console.error('下载日志文件失败:', error)
      ElMessage.error('下载文件失败')
    }
  }

  const getOperatorTypeText = (row: OperationLogRow) => {
    if (row.operator_type_code && operatorTypeMap[row.operator_type_code]) {
      return operatorTypeMap[row.operator_type_code]
    }
    if (row.operator_type && operatorTypeMap[row.operator_type]) {
      return operatorTypeMap[row.operator_type]
    }
    return row.operator_type || row.operator_type_code || '-'
  }

  const formatValue = (value: any): string => {
    if (value === null || value === undefined) return '空'
    if (typeof value === 'boolean') return value ? '是' : '否'
    if (typeof value === 'number') return String(value)
    if (typeof value === 'string') return value || '空'
    if (Array.isArray(value)) {
      if (value.length === 0) return '空'
      if (value.every((item) => ['string', 'number', 'boolean'].includes(typeof item))) {
        return value.map((item) => formatValue(item)).join('、')
      }
      return JSON.stringify(value)
    }
    if (typeof value === 'object') return JSON.stringify(value)
    return String(value)
  }

  const formatFieldValue = (key: string, value: any): string => {
    if (typeof value === 'string' && (key.endsWith('_at') || key.endsWith('_time'))) {
      return formatDateTime(value)
    }
    if (key === 'enable_polling') return value ? '开启' : '关闭'
    if (key === 'realname_policy') return realnamePolicyMap[value] || formatValue(value)
    if (key === 'real_name_status') return value === 1 ? '已实名' : '未实名'
    if (key === 'switch_mode') {
      return String(value) === '0' ? '自动' : String(value) === '1' ? '手动' : formatValue(value)
    }
    if (key === 'new_status') return newStatusMap[value] || formatValue(value)
    if (key === 'network_status') {
      return Number(value) === 1 ? '正常' : Number(value) === 0 ? '停机' : formatValue(value)
    }
    if (key === 'stop_reason') return stopReasonMap[String(value ?? '')] ?? formatValue(value)
    if (key === 'asset_type') return assetTypeMap[String(value)] || formatValue(value)
    if (key === 'card_category') return cardCategoryMap[String(value)] || formatValue(value)
    if (key === 'status') return assetStatusMap[String(value)] || formatValue(value)
    if (key === 'source_service') return value === 'asset_polling' ? '资产轮询' : formatValue(value)
    return formatValue(value)
  }

  const sanitizeFieldName = (fieldName: string): string => {
    return fieldName
      .trim()
      .replace(/（[^）]*）/g, '')
      .trim()
  }

  const shouldHideIdField = (key: string, fieldName: string): boolean => {
    const normalizedKey = key.trim()
    const normalizedKeyLower = normalizedKey.toLowerCase()
    const normalizedFieldName = sanitizeFieldName(fieldName)
    const normalizedFieldNameUpper = normalizedFieldName.toUpperCase()

    const visibleIdentifierKeys = new Set(['iccid', 'msisdn', 'imei', 'imsi', 'sn'])
    const visibleIdentifierNames = ['ICCID', 'MSISDN', 'IMEI', 'IMSI', 'SN']

    if (
      visibleIdentifierKeys.has(normalizedKeyLower) ||
      visibleIdentifierNames.some((name) => normalizedFieldNameUpper.endsWith(name))
    ) {
      return false
    }

    if (
      normalizedKeyLower === 'id' ||
      normalizedFieldName === '绑定记录ID' ||
      normalizedFieldName === 'ID'
    ) {
      return true
    }

    return (
      normalizedKeyLower.endsWith('_id') ||
      /^[a-z][a-z0-9]*Id$/.test(normalizedKey) ||
      normalizedFieldName.endsWith('ID')
    )
  }

  const extractOperationContent = (
    row: OperationLogRow,
    type: 'before' | 'after'
  ): Record<string, any> => {
    const directContent =
      type === 'before' ? row.operation_content_before : row.operation_content_after
    if (directContent && Object.keys(directContent).length > 0) {
      return directContent
    }

    const fallbackContainer = type === 'before' ? row.before_data : row.after_data
    const nestedContent = fallbackContainer?.operation_content
    if (nestedContent && Object.keys(nestedContent).length > 0) {
      return nestedContent
    }

    return fallbackContainer || {}
  }

  const isSameValue = (beforeValue: any, afterValue: any) => {
    if (beforeValue === afterValue) return true
    return JSON.stringify(beforeValue) === JSON.stringify(afterValue)
  }

  const getChangeContent = (row: OperationLogRow): ChangeItem[] => {
    const before = extractOperationContent(row, 'before')
    const after = extractOperationContent(row, 'after')
    const desc = row.operation_fields_desc || {}
    const keys = new Set([...Object.keys(before), ...Object.keys(after)])

    const changes: ChangeItem[] = []
    for (const key of keys) {
      const fieldName = sanitizeFieldName(desc[key] || fieldNameMap[key] || key)
      if (shouldHideIdField(key, fieldName)) continue

      const beforeValue = before[key]
      const afterValue = after[key]
      if (isSameValue(beforeValue, afterValue)) continue

      changes.push({
        type: 'change',
        key,
        fieldName,
        beforeValue,
        afterValue
      })
    }

    return changes
  }

  const getMessageItems = (row: OperationLogRow): MessageItem[] => {
    const items: MessageItem[] = []
    const seen = new Set<string>()

    const pushMessage = (
      key: string,
      fieldName: string,
      message?: string,
      level: 'info' | 'error' = 'info'
    ) => {
      const normalizedMessage = message?.trim()
      if (!normalizedMessage) return

      const duplicateKey = `${fieldName}:${normalizedMessage}`
      if (seen.has(duplicateKey)) return
      seen.add(duplicateKey)

      items.push({
        type: 'message',
        key,
        fieldName,
        message: normalizedMessage,
        level
      })
    }

    pushMessage('error_msg', '失败原因', row.error_msg, 'error')
    pushMessage('reason', '原因说明', row.reason, row.result_status === 'failed' ? 'error' : 'info')

    if (row.fail_count > 0) {
      pushMessage('fail_count', '批量结果', `失败 ${row.fail_count} 项`, 'error')
    }

    row.failed_items?.slice(0, 3).forEach((item, index) => {
      const detail = item?.iccid
        ? `${item.iccid}：${item.reason || '未知原因'}`
        : item?.reason || ''
      pushMessage(`failed_items_${index}`, '失败明细', detail, 'error')
    })

    if (!items.length && row.result_status === 'failed') {
      pushMessage('result_status', '执行结果', '执行失败', 'error')
    }

    if (!items.length && row.result_status === 'denied') {
      pushMessage('result_status', '执行结果', '操作被拒绝', 'info')
    }

    return items
  }

  const getDisplayContent = (row: OperationLogRow): DisplayItem[] => {
    return [...getChangeContent(row), ...getMessageItems(row)]
  }

  watch(
    () => props.assetIdentifier,
    (newVal) => {
      if (newVal) {
        loadLogs()
      }
    },
    { immediate: true }
  )
</script>

<style scoped lang="scss">
  .operation-logs-card {
    .card-header {
      display: flex;
      flex-wrap: wrap;
      gap: 12px;
      align-items: center;
      justify-content: space-between;

      .header-title {
        font-size: 16px;
        font-weight: 500;
      }

      .filter-section {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        align-items: center;
        justify-content: flex-end;
        min-width: 0;

        .operation-type-select {
          width: 180px;
        }

        .result-status-select {
          width: 120px;
        }
      }
    }

    .logs-table-wrapper {
      overflow-x: auto;

      .logs-table {
        min-width: 980px;

        :deep(.el-table__header-wrapper) {
          th {
            background-color: var(--el-fill-color-light);
          }
        }

        .change-content {
          display: flex;
          flex-direction: column;
          gap: 4px;

          .change-item {
            display: flex;
            gap: 4px;
            align-items: center;
            font-size: 12px;

            .field-name {
              min-width: 72px;
              color: var(--el-text-color-secondary);
            }

            .field-value {
              display: flex;
              flex-wrap: wrap;
              gap: 4px;
              align-items: center;
              word-break: break-all;

              .new-value {
                color: var(--el-color-success);
              }

              .message-value {
                color: var(--el-text-color-regular);

                &.is-error {
                  color: var(--el-color-danger);
                }
              }
            }
          }
        }
      }

      .logs-pagination {
        justify-content: flex-end;
        margin-top: 16px;
      }
    }

    @media (width <= 1200px) {
      .card-header {
        flex-direction: column;
        align-items: stretch;

        .filter-section {
          justify-content: flex-start;
          width: 100%;
        }
      }
    }

    @media (width <= 768px) {
      .card-header {
        flex-direction: column;
        align-items: stretch;

        .filter-section {
          flex-direction: column;
          align-items: stretch;

          :deep(.el-select),
          .el-button,
          .el-tag {
            width: 100% !important;
          }

          .el-button {
            margin-left: 0;
          }
        }
      }

      .logs-table-wrapper {
        padding: 0 12px;
        margin-right: -12px;
        margin-left: -12px;

        :deep(.el-pagination) {
          justify-content: flex-start !important;
          overflow-x: auto;
        }
      }
    }
  }
</style>
