<script setup lang="ts">
import { ref, watch } from 'vue';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
import BusinessFormSection from '@/components/custom/business-form-section.vue';
import DictText from '@/components/custom/dict-text.vue';
import { type LogDetailField, type LogDetailSection, formatDateTime, formatMultilineText, formatText } from '../shared';

defineOptions({ name: 'LogDetailDialog' });

type DetailRecord = { id: string };

const visible = defineModel<boolean>('visible', { default: false });

const props = defineProps<{
  title: string;
  rowData?: { id: string } | null;
  sections: LogDetailSection[];
  fetchDetail: (id: string) => Promise<{
    error: unknown;
    data: DetailRecord | null;
  }>;
}>();

const loading = ref(false);
const detail = ref<DetailRecord | null>(null);

watch(
  () => [visible.value, props.rowData?.id] as const,
  ([isVisible]) => {
    if (!isVisible) return;
    loadDetail();
  }
);

async function loadDetail() {
  if (!props.rowData?.id) {
    detail.value = null;
    return;
  }

  loading.value = true;
  const result = await props.fetchDetail(props.rowData.id);
  loading.value = false;

  detail.value = !result.error && result.data ? result.data : null;
}

function getFieldValue(field: LogDetailField) {
  if (!detail.value || !field.key) return undefined;
  return (detail.value as Record<string, unknown>)[field.key];
}

function getDictFieldValue(field: LogDetailField): string | number | null | undefined {
  const value = getFieldValue(field);

  if (value === null || value === undefined) {
    return value;
  }

  return typeof value === 'string' || typeof value === 'number' ? value : String(value);
}

function getFieldText(field: LogDetailField) {
  if (field.formatter && detail.value) {
    return field.formatter(detail.value);
  }

  const value = getFieldValue(field);

  if (field.type === 'datetime') {
    return formatDateTime(value as string | null | undefined);
  }

  if (field.type === 'multiline') {
    return formatMultilineText(value);
  }

  return formatText(value);
}

function getFieldSpan(field: LogDetailField) {
  return field.span || (field.type === 'multiline' ? 2 : 1);
}
</script>

<template>
  <BusinessFormDialog v-model="visible" :title="title" preset="lg" :loading="loading" :show-footer="false">
    <div v-if="detail" class="log-detail-dialog">
      <BusinessFormSection v-for="section in sections" :key="section.title" :title="section.title">
        <ElDescriptions class="log-detail-dialog__descriptions" :column="2" border size="small">
          <ElDescriptionsItem
            v-for="field in section.fields"
            :key="`${section.title}-${field.label}`"
            :label="field.label"
            label-class-name="log-detail-dialog__label"
            :span="getFieldSpan(field)"
          >
            <DictText v-if="field.type === 'dict'" :dict-code="field.dictCode!" :value="getDictFieldValue(field)" />
            <div v-else-if="field.type === 'multiline'" class="log-detail-dialog__multiline">
              {{ getFieldText(field) }}
            </div>
            <span v-else>{{ getFieldText(field) }}</span>
          </ElDescriptionsItem>
        </ElDescriptions>
      </BusinessFormSection>
    </div>
    <ElEmpty v-else description="暂无日志详情" />
  </BusinessFormDialog>
</template>

<style scoped>
.log-detail-dialog {
  min-width: 0;
}

:deep(.log-detail-dialog__descriptions .el-descriptions__cell) {
  line-height: 1.7;
  vertical-align: middle;
}

:deep(.log-detail-dialog__label) {
  width: 120px;
  min-width: 120px;
  white-space: nowrap;
  vertical-align: middle;
}

.log-detail-dialog__multiline {
  padding: 10px 12px;
  border-radius: 6px;
  background: var(--el-fill-color-light);
  color: var(--el-text-color-regular);
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}
</style>
