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

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

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

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

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

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

const saving = ref(false);

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

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

// 从目标 URL 派生 slug 建议值：优先取路径最后一段，其次取主机名
function deriveSlugFromUrl(url: string): string {
  try {
    const parsed = new URL(url.trim());
    const raw =
      parsed.pathname
        .split('/')
        .filter(Boolean)
        .pop() ?? parsed.hostname;
    const slug = raw
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-+|-+$/g, '')
      .slice(0, 64)
      .replace(/^-+|-+$/g, '');
    return SLUG_PATTERN.test(slug) ? slug : '';
  } catch {
    return '';
  }
}

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

function isValidTargetUrl(url: string): boolean {
  try {
    const parsed = new URL(url);
    return (
      (parsed.protocol === 'http:' || parsed.protocol === 'https:') &&
      !!parsed.hostname
    );
  } catch {
    return false;
  }
}

async function handleSave() {
  const displayName = form.value.displayName.trim();
  const slug = form.value.slug.trim();
  const targetUrl = (form.value.targetUrl ?? '').trim();
  if (!displayName) {
    Toast.warning('请填写链接名称');
    return;
  }
  if (!slug) {
    Toast.warning('请填写 slug');
    return;
  }
  if (!isEdit.value && !SLUG_PATTERN.test(slug)) {
    Toast.warning(
      'slug 只能包含小写字母、数字和中划线，且必须以字母或数字开头（最长 64 位）'
    );
    return;
  }
  if (!isValidTargetUrl(targetUrl)) {
    Toast.warning('目标链接必须是合法的 http/https 地址');
    return;
  }

  saving.value = true;
  try {
    if (isEdit.value && props.link) {
      const payload: ProtectedLinkSpec = {
        ...props.link.spec,
        displayName,
        description: form.value.description?.trim() ?? '',
        targetUrl,
        requireEmailVerify: form.value.requireEmailVerify,
        enabled: form.value.enabled,
      };
      const saved = await updateLink(props.link.metadata.name, payload);
      Toast.success('链接已更新');
      emit('saved', saved, false);
    } else {
      const saved = await createLink({
        slug,
        displayName,
        description: form.value.description?.trim() ?? '',
        targetUrl,
        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="link-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="例如：内部文档"
        />
      </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="例如：internal-docs（访问链接为 /link/{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">
          目标链接 <span class="required">*</span>
        </label>
        <input
          v-model="form.targetUrl"
          class="form-input"
          type="url"
          placeholder="https://example.com/secret-page"
          @blur="
            if (!isEdit && !form.slug && form.targetUrl) {
              form.slug = deriveSlugFromUrl(form.targetUrl) || randomSlug();
            }
          "
        />
        <div class="form-hint">
          访客完成验证后将被 302 跳转到该地址；真实地址不会在门禁页展示
        </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">
        <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>
</template>

<style scoped>
.link-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;
}
</style>
