<!-- 剧本分析列表页，负责分析记录管理和模型配置入口。 -->
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { Setting } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import { FileSearch, Plus, Trash2 } from "@/icons";
import { useRouter } from "vue-router";
import ProjectSearchField from "@/components/ProjectSearchField.vue";
import CreativeShell from "@/components/creative/CreativeShell.vue";
import ModelConfigDialog from "@/components/creative/ModelConfigDialog.vue";
import { creativeApi, type CreativeOptions, type ModelConfig, type ScriptAnalysis } from "@/api/creative";
import { apiError } from "@/api/http";
import { useToastStore } from "@/stores/toast";
import { formatDateTime } from "@/utils/datetime";
import { useModelPrompts } from "@/composables/useModelPrompts";
import { ensureScriptAnalysisTextModel } from "@/utils/scriptAnalysisModel";

const router = useRouter();
const toast = useToastStore();
const scripts = ref<ScriptAnalysis[]>([]);
const options = ref<CreativeOptions>({ styles: [], models: [] });
const modelConfigs = ref<ModelConfig[]>([]);
const loading = ref(false);
const creating = ref(false);
const modelsOpen = ref(false);
const savingModels = ref(false);
const keyword = ref("");
const filteredScripts = computed(() => {
  const value = keyword.value.trim().toLocaleLowerCase();
  if (!value) return scripts.value;
  return scripts.value.filter((script) => (script.name || "未命名剧本").toLocaleLowerCase().includes(value));
});
const { prompts, promptSelections, loadPrompts, selectPrompt, createPrompt, updatePrompt, deletePrompt } =
  useModelPrompts();

function showError(error: unknown, title = "加载失败") {
  const detail = apiError(error);
  toast.error(detail.message, detail.copyText, title);
}
async function load() {
  loading.value = true;
  try {
    const [loadedScripts, loadedOptions, loadedConfigs] = await Promise.all([
      creativeApi.scriptAnalyses(),
      creativeApi.options(),
      creativeApi.userModelConfigs("script_analysis"),
    ]);
    scripts.value = loadedScripts;
    options.value = loadedOptions;
    modelConfigs.value = await ensureScriptAnalysisTextModel(loadedOptions, loadedConfigs);
    await loadPrompts(["剧本分析"]);
  } catch (error) {
    showError(error);
  } finally {
    loading.value = false;
  }
}
async function saveModels(payload: Record<string, any>) {
  const modelId = payload.prompt_reverse?.model_id;
  if (!modelId) return toast.warning("请选择文本模型");
  savingModels.value = true;
  try {
    await creativeApi.saveUserModelConfig("script_analysis", "text", modelId);
    modelConfigs.value = await creativeApi.userModelConfigs("script_analysis");
    modelsOpen.value = false;
    toast.success("模型配置已保存");
  } catch (error) {
    showError(error, "保存模型配置失败");
  } finally {
    savingModels.value = false;
  }
}
async function createScript() {
  if (creating.value) return;
  creating.value = true;
  try {
    const script = await creativeApi.createScriptAnalysis();
    await router.push({ name: "script-analysis-workbench", params: { scriptId: script.id } });
  } catch (error) {
    showError(error, "创建失败");
  } finally {
    creating.value = false;
  }
}
async function removeScript(script: ScriptAnalysis) {
  try {
    await ElMessageBox.confirm(`确定删除“${script.name}”吗？`, "删除剧本", {
      type: "warning",
      confirmButtonText: "删除",
      cancelButtonText: "取消",
    });
    await creativeApi.deleteScriptAnalysis(script.id);
    toast.success("剧本已删除");
    await load();
  } catch (error) {
    if (error !== "cancel" && error !== "close") showError(error, "删除失败");
  }
}
onMounted(load);
</script>
<template>
  <CreativeShell>
    <section class="script-toolbar">
      <ProjectSearchField
        v-model="keyword"
        placeholder="搜索剧本名称"
      />
      <div class="creative-page-actions">
        <span class="script-count">{{ filteredScripts.length }} 个剧本</span>
        <el-button @click="modelsOpen = true"
          ><el-icon><Setting /></el-icon>模型配置</el-button
        >
        <el-button
          type="primary"
          :loading="creating"
          @click="createScript"
        >
          <Plus :size="16" />新建剧本
        </el-button>
      </div>
    </section>

    <section
      v-loading="loading"
      class="script-grid"
    >
      <article
        v-for="script in filteredScripts"
        :key="script.id"
        class="script-card"
        @click="router.push({ name: 'script-analysis-workbench', params: { scriptId: script.id } })"
      >
        <div class="script-card__icon"><FileSearch :size="22" /></div>
        <div class="script-card__body">
          <strong>{{ script.name || "未命名剧本" }}</strong>
          <time>{{ formatDateTime(script.updated_at) }}</time>
        </div>
        <button
          type="button"
          class="script-card__delete"
          title="删除剧本"
          @click.stop="removeScript(script)"
        >
          <Trash2 :size="17" />
        </button>
      </article>
      <div
        v-if="!loading && !filteredScripts.length"
        class="script-empty"
      >
        <FileSearch
          :size="40"
          stroke-width="1.2"
        />
        <strong>{{ keyword.trim() ? "没有匹配的剧本" : "还没有剧本" }}</strong>
        <p>{{ keyword.trim() ? "换一个关键词继续查找" : "新建剧本后即可开始分析" }}</p>
        <el-button
          v-if="!keyword.trim()"
          type="primary"
          :loading="creating"
          @click="createScript"
        >
          <Plus :size="16" />新建剧本
        </el-button>
      </div>
    </section>
    <ModelConfigDialog
      v-model="modelsOpen"
      analysis-only
      project-type="script_analysis"
      :options="options"
      :configs="modelConfigs"
      :saving="savingModels"
      :prompts="prompts"
      :prompt-selections="promptSelections"
      @save="saveModels"
      @prompt-select="selectPrompt"
      @prompt-create="createPrompt"
      @prompt-update="updatePrompt"
      @prompt-delete="deletePrompt"
    />
  </CreativeShell>
</template>

<style scoped lang="scss">
.script-toolbar {
  min-height: var(--control-height-lg);
  margin-bottom: var(--space-xl);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xl);
}
.script-toolbar .creative-page-actions {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}
.script-count {
  color: var(--web-project-count);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-regular);
  white-space: nowrap;
}
.script-grid {
  min-height: 260px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  align-items: start;
  gap: var(--space-lg);
}
.script-card {
  min-width: 0;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  gap: 13px;
  position: relative;
  color: var(--creative-text);
  background: var(--creative-surface);
  border: 1px solid var(--creative-line);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition:
    border-color 0.18s,
    background-color 0.18s;
}
.script-card:hover {
  background: var(--web-hover);
  border-color: var(--creative-accent);
}
.script-card__icon {
  width: 42px;
  height: 42px;
  flex: 0 0 42px;
  display: grid;
  place-items: center;
  color: var(--creative-accent);
  background: color-mix(in srgb, var(--creative-accent) 12%, transparent);
  border-radius: 9px;
}
.script-card__body {
  min-width: 0;
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 6px;
}
.script-card__body strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
}
.script-card__body time {
  color: var(--creative-muted);
  font-size: 12px;
}
.script-card__delete {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  color: var(--creative-muted);
  background: transparent;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  opacity: 1;
  pointer-events: auto;
  transition:
    color 0.18s,
    background-color 0.18s;
}
.script-card__delete:hover {
  color: var(--web-danger);
  background: color-mix(in srgb, var(--web-danger) 12%, transparent);
}
.script-empty {
  min-height: 260px;
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  color: var(--creative-muted);
  text-align: center;
}
.script-empty strong {
  color: var(--creative-text);
  font-size: 16px;
}
.script-empty p {
  margin: 0;
  font-size: 12px;
}
.script-empty :deep(.el-button) {
  margin-top: var(--space-sm);
}
@media (max-width: 767px) {
  .script-toolbar {
    align-items: stretch;
    flex-direction: column;
    gap: var(--space-md);
  }
  .script-toolbar :deep(.project-search-field),
  .script-toolbar .creative-page-actions {
    width: 100%;
  }
  .script-toolbar .creative-page-actions {
    justify-content: space-between;
  }
  .script-toolbar :deep(.el-button) {
    flex: 1;
  }
  .script-grid {
    grid-template-columns: 1fr;
  }
}
</style>
