<!-- 重绘项目详情页，负责项目剧集、配置和工作台入口。 -->
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { Plus, Setting } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import { ArrowLeft, Film, Trash2 } from "@/icons";
import { useRoute, useRouter } from "vue-router";
import ProjectSearchField from "@/components/ProjectSearchField.vue";
import CreativeShell from "@/components/creative/CreativeShell.vue";
import LoadingMedia from "@/components/creative/LoadingMedia.vue";
import ModelConfigDialog from "@/components/creative/ModelConfigDialog.vue";
import { creativeApi, type CreativeOptions, type Episode, type ProjectDetail } from "@/api/creative";
import { apiError } from "@/api/http";
import { useModelPrompts } from "@/composables/useModelPrompts";
import { useToastStore } from "@/stores/toast";
import { formatDateTime } from "@/utils/datetime";
import { firstVideoFrameURL } from "@/utils/media";

const route = useRoute();
const router = useRouter();
const toast = useToastStore();
const projectId = String(route.params.projectId);
const project = ref<ProjectDetail>();
const options = ref<CreativeOptions>({ styles: [], models: [] });
const loading = ref(false);
const creating = ref(false);
const modelsOpen = ref(false);
const savingModels = ref(false);
const keyword = ref("");
const modelReady = computed(() =>
  project.value?.model_configs.some((item) => item.purpose === "prompt_reverse" && Boolean(item.model_id)),
);
const filteredEpisodes = computed(() => {
  const value = keyword.value.trim().toLocaleLowerCase();
  const episodes = project.value?.episodes || [];
  if (!value) return episodes;
  return episodes.filter(
    (episode) =>
      episode.name.toLocaleLowerCase().includes(value) ||
      String(episode.episode_no).includes(value) ||
      `第${episode.episode_no}集`.includes(value.replaceAll(" ", "")),
  );
});
const { prompts, promptSelections, loadPrompts, selectPrompt, createPrompt, updatePrompt, deletePrompt } =
  useModelPrompts();

const statusLabels: Record<string, { label: string; tone: string }> = {
  draft: { label: "待上传", tone: "is-draft" },
  uploaded: { label: "待反推", tone: "is-uploaded" },
  analyzing: { label: "分镜反推中", tone: "is-analyzing" },
  review: { label: "待反推剧本", tone: "is-ready" },
  generating: { label: "剧本反推中", tone: "is-generating" },
  failed: { label: "处理失败", tone: "is-failed" },
};

/** 根据后端处理阶段和剧本产出标记生成剧集卡片的业务状态。 */
function episodeStatus(episode: Episode) {
  if (episode.status === "review" && episode.has_redraw_script) {
    return { label: "已完成", tone: "is-completed" };
  }
  return statusLabels[episode.status] || { label: episode.status, tone: "is-draft" };
}

async function load() {
  loading.value = true;
  try {
    const [loadedProject, loadedOptions] = await Promise.all([creativeApi.project(projectId), creativeApi.options()]);
    options.value = loadedOptions;
    project.value = loadedProject;
    if (project.value.project_type !== "video_redraw") {
      await router.replace({ name: "drama-project", params: { projectId } });
      return;
    }
    const configured = project.value.model_configs.some(
      (item) => item.purpose === "prompt_reverse" && Boolean(item.model_id),
    );
    if (!configured) {
      const defaultModel = loadedOptions.models.find((item) => item.model_type === "text" && item.multimodal);
      if (defaultModel) {
        await creativeApi.saveModels(projectId, {
          prompt_reverse: { model_id: defaultModel.id, settings: { prompt: "" } },
        });
        project.value = await creativeApi.project(projectId);
      }
    }
  } catch (error) {
    showError(error, "加载项目失败");
  } finally {
    loading.value = false;
  }
}

async function openModels() {
  modelsOpen.value = true;
  await loadPrompts(["剧本反推"]);
}

async function saveModels(payload: Record<string, any>) {
  const value = payload.prompt_reverse;
  if (!value?.model_id) return toast.warning("请选择反推模型");
  savingModels.value = true;
  try {
    await creativeApi.saveModels(projectId, { prompt_reverse: value });
    modelsOpen.value = false;
    toast.success("模型配置已保存");
    await load();
  } catch (error) {
    showError(error, "保存模型配置失败");
  } finally {
    savingModels.value = false;
  }
}

async function createEpisode() {
  if (creating.value) return;
  creating.value = true;
  try {
    const episode = await creativeApi.createEpisode(projectId);
    toast.success(`第 ${episode.episode_no} 集已创建`);
    await router.push({
      name: "redraw-workbench",
      params: { projectId, episodeId: episode.id },
    });
  } catch (error) {
    showError(error, "创建剧集失败");
  } finally {
    creating.value = false;
  }
}

async function openEpisode(episodeId: string) {
  await router.push({ name: "redraw-workbench", params: { projectId, episodeId } });
}

async function removeEpisode(episodeId: string, episodeNo: number) {
  try {
    await ElMessageBox.confirm(`确定删除第 ${episodeNo} 集吗？`, "删除剧集", {
      type: "warning",
      confirmButtonText: "删除",
      cancelButtonText: "取消",
    });
    await creativeApi.deleteEpisode(projectId, episodeId);
    toast.success("剧集已删除");
    await load();
  } catch (error) {
    if (error !== "cancel" && error !== "close") showError(error, "删除剧集失败");
  }
}

function showError(error: unknown, title: string) {
  const detail = apiError(error);
  toast.error(detail.message, detail.copyText, title);
}

onMounted(load);
</script>

<template>
  <CreativeShell page-title="剧本反推">
    <section class="redraw-project-header">
      <RouterLink
        class="redraw-project-back"
        :to="{ name: 'redraw-projects' }"
      >
        <ArrowLeft :size="18" />
      </RouterLink>
      <div class="redraw-project-heading">
        <strong>{{ project?.name || "项目" }}</strong>
      </div>
      <div class="redraw-project-actions creative-page-actions">
        <el-button
          :icon="Setting"
          :class="{ 'model-warning': !modelReady }"
          @click="openModels"
        >
          模型配置
        </el-button>
        <el-button
          type="primary"
          :icon="Plus"
          :loading="creating"
          @click="createEpisode"
        >
          创建剧集
        </el-button>
      </div>
    </section>

    <section class="redraw-episode-toolbar">
      <ProjectSearchField
        v-model="keyword"
        placeholder="搜索剧集名称或集数"
      />
      <span>{{ filteredEpisodes.length }} 个剧集</span>
    </section>

    <section
      v-loading="loading"
      class="redraw-episode-grid"
    >
      <article
        v-for="episode in filteredEpisodes"
        :key="episode.id"
        class="redraw-episode-card"
        @click="openEpisode(episode.id)"
      >
        <div class="redraw-episode-cover">
          <LoadingMedia
            v-if="episode.source_video_url"
            type="video"
            :src="firstVideoFrameURL(episode.source_video_url)"
            muted
            playsinline
            preload="metadata"
          />
          <Film
            v-else
            :size="34"
            stroke-width="1.25"
          />
          <span :class="['redraw-episode-status', episodeStatus(episode).tone]">
            {{ episodeStatus(episode).label }}
          </span>
        </div>
        <div class="redraw-episode-copy">
          <div>
            <strong>{{ episode.name }}</strong>
          </div>
          <button
            type="button"
            @click.stop="removeEpisode(episode.id, episode.episode_no)"
          >
            <Trash2 :size="16" />
          </button>
        </div>
        <div class="redraw-episode-meta">
          <span>{{ episode.storyboard_count || 0 }} 个分镜</span>
          <time>{{ formatDateTime(episode.updated_at || project?.updated_at || "") }}</time>
        </div>
      </article>

      <div
        v-if="!loading && !filteredEpisodes.length"
        class="redraw-episode-empty"
      >
        <Film
          :size="38"
          stroke-width="1.2"
        />
        <strong>{{ keyword.trim() ? "没有匹配的剧集" : "还没有剧集" }}</strong>
        <p>{{ keyword.trim() ? "换一个关键词继续查找" : "创建第一集后上传原视频开始反推" }}</p>
        <el-button
          v-if="!keyword.trim()"
          type="primary"
          :icon="Plus"
          :loading="creating"
          @click="createEpisode"
        >
          创建剧集
        </el-button>
      </div>
    </section>
    <ModelConfigDialog
      v-if="project"
      v-model="modelsOpen"
      analysis-only
      :options="options"
      :configs="project.model_configs"
      :prompts="prompts"
      :prompt-selections="promptSelections"
      :saving="savingModels"
      @save="saveModels"
      @prompt-select="selectPrompt"
      @prompt-create="createPrompt"
      @prompt-update="updatePrompt"
      @prompt-delete="deletePrompt"
    />
  </CreativeShell>
</template>

<style scoped lang="scss" src="./RedrawProjectView.styles.scss"></style>
