<script setup lang="ts">
import type {SkillFileContent, SkillFileNode, SkillInfo} from './types';

import {computed, onMounted, ref, watch} from 'vue';
import {useRoute, useRouter} from 'vue-router';

import DOMPurify from 'dompurify';
import {ArrowLeft, Check, Download, Promotion} from '@element-plus/icons-vue';
import {ElButton, ElEmpty, ElImage, ElMessage, ElTag, ElTree,} from 'element-plus';
import MarkdownIt from 'markdown-it';

import CodeMirrorEditor from '#/components/editor/CodeMirrorEditor.vue';

import {
  getSkillDetail,
  getSkillFileContent,
  getSkillFileTree,
  resolveSkillAssetUrl,
  saveSkill,
  saveSkillFile,
  submitSkillPublishApproval,
} from './api';

const route = useRoute();
const router = useRouter();
const skillId = computed(() => String(route.params.id || 'new'));
const isNew = computed(() => skillId.value === 'new');
const skill = ref<SkillInfo>({
  displayName: '新建技能',
  skillContent: '---\nname: new-skill\ndescription: 新技能\n---\n\n# 新技能\n',
  visibilityScope: 'PRIVATE',
  enabled: true,
});
const fileTree = ref<SkillFileNode[]>([]);
const selectedFile = ref<SkillFileContent>();
const editorContent = ref('');
const loading = ref(false);
const saving = ref(false);

const markdown = new MarkdownIt({
  breaks: true,
  html: false,
  linkify: true,
});

const renderedMarkdown = computed(() => {
  if (!isMarkdownFile.value) return '';
  return DOMPurify.sanitize(markdown.render(editorContent.value || ''));
});

const isMarkdownFile = computed(() =>
  selectedFile.value?.type === 'SKILL' || selectedFile.value?.type === 'REFERENCE',
);
const isScriptFile = computed(() => selectedFile.value?.type === 'SCRIPT');
const isAssetFile = computed(() => selectedFile.value?.type === 'ASSET');
const assetUrl = computed(() =>
  selectedFile.value?.path && !isNew.value
    ? resolveSkillAssetUrl(skillId.value, selectedFile.value.path)
    : '',
);
const isImageAsset = computed(() =>
  String(selectedFile.value?.mediaType || '').startsWith('image/') &&
  selectedFile.value?.mediaType !== 'image/svg+xml',
);
const isPdfAsset = computed(() => selectedFile.value?.mediaType === 'application/pdf');

onMounted(initPage);

watch(skillId, initPage);

async function initPage() {
  if (isNew.value) {
    const defaultContent = '---\nname: new-skill\ndescription: 新技能\n---\n\n# 新技能\n';
    skill.value = {
      displayName: '新建技能',
      skillContent: defaultContent,
      visibilityScope: 'PRIVATE',
      enabled: true,
    };
    selectedFile.value = { path: 'SKILL.md', type: 'SKILL', content: defaultContent };
    editorContent.value = defaultContent;
    fileTree.value = [
      { key: 'SKILL.md', path: 'SKILL.md', name: 'SKILL.md', type: 'SKILL' },
      { key: 'references', path: 'references', name: 'references/', type: 'DIRECTORY', children: [] },
      { key: 'scripts', path: 'scripts', name: 'scripts/', type: 'DIRECTORY', children: [] },
      { key: 'assets', path: 'assets', name: 'assets/', type: 'DIRECTORY', children: [] },
    ];
    return;
  }
  await loadDetail();
}

async function loadDetail() {
  loading.value = true;
  try {
    const detailRes = await getSkillDetail(skillId.value);
    if (detailRes.errorCode === 0) {
      skill.value = detailRes.data;
    }
    await loadTree();
    await selectFile('SKILL.md');
  } finally {
    loading.value = false;
  }
}

async function loadTree() {
  const res = await getSkillFileTree(skillId.value);
  if (res.errorCode === 0) {
    fileTree.value = res.data || [];
  }
}

async function selectFile(path: string) {
  if (isNew.value) return;
  const res = await getSkillFileContent(skillId.value, path);
  if (res.errorCode === 0) {
    selectedFile.value = res.data;
    editorContent.value = res.data.content || '';
  }
}

function handleTreeNodeClick(node: SkillFileNode) {
  if (node.type === 'DIRECTORY') return;
  selectFile(node.path);
}

async function handleSave() {
  saving.value = true;
  try {
    if (isNew.value) {
      skill.value.skillContent = editorContent.value;
      const res = await saveSkill(skill.value);
      if (res.errorCode === 0) {
        ElMessage.success('保存成功');
        await router.replace(`/ai/skill/detail/${res.data.id}`);
      }
      return;
    }
    if (!selectedFile.value) return;
    if (isMarkdownFile.value || isScriptFile.value) {
      const res = await saveSkillFile(skillId.value, selectedFile.value.path, editorContent.value);
      if (res.errorCode === 0) {
        selectedFile.value = res.data;
        ElMessage.success('保存成功');
        await loadTree();
        if (selectedFile.value.path === 'SKILL.md') {
          await loadDetail();
        }
      }
    }
  } finally {
    saving.value = false;
  }
}

async function handlePublish() {
  if (isNew.value) {
    ElMessage.warning('请先保存技能');
    return;
  }
  const res = await submitSkillPublishApproval(skillId.value);
  if (res.errorCode === 0) {
    ElMessage.success(res.message || '操作成功');
    await loadDetail();
  }
}

function editorLanguage() {
  const language = selectedFile.value?.language;
  if (language === 'PYTHON') return 'python';
  if (language === 'JAVASCRIPT') return 'javascript';
  if (language === 'SHELL') return 'shell';
  if (isMarkdownFile.value) return 'markdown';
  return 'text';
}
</script>

<template>
  <div class="skill-detail-page" v-loading="loading">
    <header class="skill-detail-page__header">
      <div class="skill-detail-page__title">
        <ElButton :icon="ArrowLeft" text @click="router.push('/ai/skill')" />
        <div>
          <h1>{{ skill.displayName || skill.name || '技能详情' }}</h1>
          <p>{{ skill.description || '未填写描述' }}</p>
        </div>
        <ElTag v-if="skill.displayPublishStatus || skill.publishStatus" size="small" effect="plain">
          {{ skill.displayPublishStatus || skill.publishStatus }}
        </ElTag>
      </div>
      <div class="skill-detail-page__actions">
        <ElButton :icon="Check" type="primary" :loading="saving" @click="handleSave">
          保存
        </ElButton>
        <ElButton :icon="Promotion" @click="handlePublish">发布</ElButton>
      </div>
    </header>

    <main class="skill-detail-page__body">
      <aside class="skill-detail-page__tree">
        <ElTree
          node-key="path"
          :data="fileTree"
          :props="{ label: 'name', children: 'children' }"
          default-expand-all
          highlight-current
          @node-click="handleTreeNodeClick"
        />
      </aside>

      <section class="skill-detail-page__workspace">
        <template v-if="selectedFile">
          <div class="skill-detail-page__filebar">
            <strong>{{ selectedFile.path }}</strong>
            <span v-if="selectedFile.size">{{ selectedFile.size }} bytes</span>
          </div>

          <div v-if="isMarkdownFile" class="skill-detail-page__split">
            <CodeMirrorEditor
              v-model="editorContent"
              class="skill-detail-page__editor"
              :language="editorLanguage()"
            />
            <div class="skill-detail-page__preview markdown-body" v-html="renderedMarkdown"></div>
          </div>

          <CodeMirrorEditor
            v-else-if="isScriptFile"
            v-model="editorContent"
            class="skill-detail-page__editor"
            :language="editorLanguage()"
          />

          <div v-else-if="isAssetFile" class="skill-detail-page__asset">
            <ElImage v-if="isImageAsset" :src="assetUrl" fit="contain" />
            <iframe v-else-if="isPdfAsset" :src="assetUrl"></iframe>
            <div v-else class="skill-detail-page__asset-info">
              <p>{{ selectedFile.mediaType || 'application/octet-stream' }}</p>
              <p>{{ selectedFile.size || 0 }} bytes</p>
            </div>
            <ElButton :icon="Download" tag="a" :href="assetUrl" target="_blank">
              下载
            </ElButton>
          </div>
        </template>
        <ElEmpty v-else />
      </section>
    </main>
  </div>
</template>

<style scoped>
.skill-detail-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
  padding: 24px;
}

.skill-detail-page__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.skill-detail-page__title {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.skill-detail-page__title h1 {
  margin: 0;
  font-size: 20px;
  font-weight: 650;
  line-height: 28px;
}

.skill-detail-page__title p {
  margin: 2px 0 0;
  color: var(--el-text-color-secondary);
}

.skill-detail-page__actions {
  display: flex;
  gap: 8px;
}

.skill-detail-page__body {
  display: flex;
  flex: 1;
  gap: 16px;
  min-height: 0;
}

.skill-detail-page__tree {
  width: 280px;
  min-width: 240px;
  padding: 12px;
  overflow: auto;
  background: var(--el-bg-color);
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
}

.skill-detail-page__workspace {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--el-bg-color);
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
}

.skill-detail-page__filebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 48px;
  padding: 0 16px;
  border-bottom: 1px solid var(--el-border-color-lighter);
}

.skill-detail-page__filebar span {
  color: var(--el-text-color-secondary);
}

.skill-detail-page__split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
  min-height: 0;
  padding: 16px;
  flex: 1;
}

.skill-detail-page__editor {
  flex: 1;
  min-height: 0;
  margin: 16px;
}

.skill-detail-page__split .skill-detail-page__editor {
  margin: 0;
}

.skill-detail-page__preview {
  min-height: 0;
  padding: 16px;
  overflow: auto;
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
}

.skill-detail-page__asset {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  min-height: 0;
  padding: 24px;
}

.skill-detail-page__asset :deep(.el-image) {
  width: 100%;
  max-height: 60vh;
}

.skill-detail-page__asset iframe {
  width: 100%;
  height: 60vh;
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
}

.skill-detail-page__asset-info {
  color: var(--el-text-color-secondary);
  text-align: center;
}

.markdown-body :deep(h1),
.markdown-body :deep(h2),
.markdown-body :deep(h3) {
  margin: 0 0 12px;
}

.markdown-body :deep(p) {
  line-height: 1.7;
}
</style>
