<script lang="ts" setup>
import { createResource, updateResource } from '@/api';
import type { DownloadResource, DownloadResourceSpec } from '@/types';
import { Toast, VButton, VModal, VSwitch } from '@halo-dev/components';
import { computed, ref, watch } from 'vue';

// AttachmentSelectorModal 选中的附件对象（只取需要的字段，结构向后兼容）
interface PickedAttachment {
  metadata?: { name?: string };
  spec?: {
    displayName?: string;
    size?: number;
  };
}

const props = defineProps<{
  visible: boolean;
  resource: DownloadResource | null;
}>();

const emit = defineEmits<{
  (e: 'update:visible', value: boolean): void;
  (e: 'saved', resource: DownloadResource, created: boolean): void;
}>();

const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;

const isEdit = computed(() => props.resource !== null);

const form = ref<DownloadResourceSpec>({
  slug: '',
  displayName: '',
  description: '',
  attachmentName: '',
  requireEmailVerify: false,
  enabled: true,
});

// 本次从附件选择器里选到的附件（用于展示文件名 + 大小）
const pickedAttachment = ref<PickedAttachment | null>(null);
const attachmentSelectorVisible = ref(false);
const saving = ref(false);

watch(
  () => props.visible,
  (visible) => {
    if (!visible) {
      return;
    }
    pickedAttachment.value = null;
    if (props.resource) {
      const spec = props.resource.spec;
      form.value = {
        slug: spec.slug,
        displayName: spec.displayName,
        description: spec.description ?? '',
        attachmentName: spec.attachmentName ?? '',
        requireEmailVerify: spec.requireEmailVerify ?? false,
        enabled: spec.enabled ?? true,
      };
    } else {
      form.value = {
        slug: '',
        displayName: '',
        description: '',
        attachmentName: '',
        requireEmailVerify: false,
        enabled: true,
      };
    }
  }
);

function close() {
  emit('update:visible', false);
}

function formatSize(size?: number): string {
  if (!size || size <= 0) {
    return '';
  }
  if (size < 1024) {
    return `${size} B`;
  }
  if (size < 1024 * 1024) {
    return `${(size / 1024).toFixed(1)} KB`;
  }
  if (size < 1024 * 1024 * 1024) {
    return `${(size / 1024 / 1024).toFixed(1)} MB`;
  }
  return `${(size / 1024 / 1024 / 1024).toFixed(2)} GB`;
}

// 从附件文件名派生 slug 建议值：取主文件名，转小写，非法字符折叠为 -
function deriveSlug(filename: string): string {
  const base = filename.replace(/\.[^.]+$/, '');
  const slug = base
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 64)
    .replace(/^-+|-+$/g, '');
  return SLUG_PATTERN.test(slug) ? slug : '';
}

function randomSlug(): string {
  return Math.random().toString(36).slice(2, 10);
}

function handleAttachmentSelect(attachments: unknown[]) {
  const attachment = attachments?.[0] as PickedAttachment | undefined;
  const name = attachment?.metadata?.name;
  if (!attachment || !name) {
    return;
  }
  pickedAttachment.value = attachment;
  form.value.attachmentName = name;
  // 新建且 slug 为空时，从文件名派生建议值；派生失败给随机短串
  if (!isEdit.value && !form.value.slug) {
    const displayName = attachment.spec?.displayName ?? name;
    form.value.slug = deriveSlug(displayName) || randomSlug();
  }
  attachmentSelectorVisible.value = false;
}

const attachmentDisplay = computed(() => {
  if (pickedAttachment.value) {
    const name =
      pickedAttachment.value.spec?.displayName ??
      pickedAttachment.value.metadata?.name ??
      '';
    const size = formatSize(pickedAttachment.value.spec?.size);
    return size ? `${name}（${size}）` : name;
  }
  return form.value.attachmentName || '';
});

async function handleSave() {
  const displayName = form.value.displayName.trim();
  const slug = form.value.slug.trim();
  if (!displayName) {
    Toast.warning('请填写资源名称');
    return;
  }
  if (!slug) {
    Toast.warning('请填写 slug');
    return;
  }
  if (!isEdit.value && !SLUG_PATTERN.test(slug)) {
    Toast.warning(
      'slug 只能包含小写字母、数字和中划线，且必须以字母或数字开头（最长 64 位）'
    );
    return;
  }

  saving.value = true;
  try {
    if (isEdit.value && props.resource) {
      const payload: DownloadResourceSpec = {
        ...props.resource.spec,
        displayName,
        description: form.value.description?.trim() ?? '',
        attachmentName: form.value.attachmentName,
        requireEmailVerify: form.value.requireEmailVerify,
        enabled: form.value.enabled,
      };
      const saved = await updateResource(props.resource.metadata.name, payload);
      Toast.success('资源已更新');
      emit('saved', saved, false);
    } else {
      const saved = await createResource({
        slug,
        displayName,
        description: form.value.description?.trim() ?? '',
        attachmentName: form.value.attachmentName,
        requireEmailVerify: form.value.requireEmailVerify,
        enabled: form.value.enabled,
      });
      Toast.success('资源已创建');
      emit('saved', saved, true);
    }
    close();
  } catch (e) {
    const err = e as {
      response?: { data?: { detail?: string; title?: string } };
      message?: string;
    };
    Toast.error(
      err?.response?.data?.detail ||
        err?.response?.data?.title ||
        err?.message ||
        '保存失败，请稍后重试'
    );
  } finally {
    saving.value = false;
  }
}
</script>

<template>
  <VModal
    :visible="visible"
    :title="isEdit ? '编辑下载资源' : '新建下载资源'"
    :width="640"
    @update:visible="emit('update:visible', $event)"
    @close="close"
  >
    <div class="resource-form">
      <div class="form-item form-item--column">
        <label class="form-label">
          资源名称 <span class="required">*</span>
        </label>
        <input
          v-model="form.displayName"
          class="form-input"
          type="text"
          placeholder="例如：产品白皮书 PDF"
        />
      </div>

      <div class="form-item form-item--column">
        <label class="form-label">
          slug <span class="required">*</span>
        </label>
        <input
          v-model="form.slug"
          class="form-input"
          type="text"
          :disabled="isEdit"
          placeholder="例如：whitepaper-2024（下载链接为 /download/{slug}）"
        />
        <div v-if="isEdit" class="form-hint">slug 创建后不可修改</div>
        <div v-else class="form-hint">
          小写字母、数字、中划线，以字母或数字开头，最长 64 位
        </div>
      </div>

      <div class="form-item form-item--column">
        <label class="form-label">描述</label>
        <textarea
          v-model="form.description"
          class="form-input"
          rows="3"
          placeholder="可选，资源用途说明"
        />
      </div>

      <div class="form-item form-item--column">
        <label class="form-label">附件</label>
        <div class="attachment-picker">
          <VButton size="sm" type="default" @click="attachmentSelectorVisible = true">
            选择附件
          </VButton>
          <span v-if="attachmentDisplay" class="attachment-name" :title="form.attachmentName">
            {{ attachmentDisplay }}
          </span>
          <span v-else class="text-sm text-gray-400">未选择</span>
        </div>
      </div>

      <div class="form-item">
        <span class="form-label">需要邮箱验证</span>
        <VSwitch v-model="form.requireEmailVerify" />
      </div>

      <div class="form-item">
        <span class="form-label">启用</span>
        <VSwitch v-model="form.enabled" />
      </div>
    </div>

    <template #footer>
      <VButton type="primary" :loading="saving" @click="handleSave">
        保存
      </VButton>
      <VButton type="default" @click="close">取消</VButton>
    </template>
  </VModal>

  <AttachmentSelectorModal
    v-model:visible="attachmentSelectorVisible"
    @select="handleAttachmentSelect"
  />
</template>

<style scoped>
.resource-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.form-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.form-item--column {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}

.form-label {
  font-size: 14px;
  color: #374151;
}

.required {
  color: #dc2626;
}

.form-input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 14px;
  outline: none;
}

.form-input:focus {
  border-color: #2563eb;
}

.form-input:disabled {
  background: #f3f4f6;
  color: #6b7280;
  cursor: not-allowed;
}

.form-hint {
  font-size: 12px;
  color: #9ca3af;
}

.attachment-picker {
  display: flex;
  align-items: center;
  gap: 10px;
}

.attachment-name {
  font-size: 13px;
  color: #374151;
  max-width: 380px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>
