<!-- 剧本导入对话框，负责从已有项目或本地文件导入剧本内容。 -->
<script setup lang="ts">
import { computed, h, ref } from "vue";
import { ElMessageBox } from "element-plus";
import { FileInput, FileText, FolderInput, Search, TriangleAlert, Upload } from "@/icons";
import { creativeApi, type ScriptAnalysis, type ScriptAnalysisImportProject } from "@/api/creative";
import { apiError } from "@/api/http";
import { useToastStore } from "@/stores/toast";
import { formatDateTime } from "@/utils/datetime";

const props = defineProps<{
  scriptId: string;
  disabled: boolean;
  beforeImport: () => Promise<boolean>;
}>();
const emit = defineEmits<{
  imported: [script: ScriptAnalysis];
}>();

const toast = useToastStore();
const menuVisible = ref(false);
const projectDialogOpen = ref(false);
const localDialogOpen = ref(false);
const projects = ref<ScriptAnalysisImportProject[]>([]);
const loadingProjects = ref(false);
const processing = ref(false);
const selectedProjectId = ref("");
const projectKeyword = ref("");
const selectedFile = ref<File | null>(null);
const fileInput = ref<HTMLInputElement | null>(null);
const selectedProject = computed(() => projects.value.find((project) => project.id === selectedProjectId.value));
const filteredProjects = computed(() => {
  const keyword = projectKeyword.value.trim().toLocaleLowerCase();
  if (!keyword) return projects.value;
  return projects.value.filter((project) => project.name.toLocaleLowerCase().includes(keyword));
});

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

async function confirmImport(sourceName: string) {
  try {
    const message = h("div", { class: "script-import-confirm__content" }, [
      h("span", { class: "script-import-confirm__icon" }, [h(TriangleAlert, { size: 22 })]),
      h("div", { class: "script-import-confirm__copy" }, [
        h("strong", `确认导入“${sourceName}”？`),
        h("p", "导入成功后将替换当前剧本原文，并清空已有分析结果。该操作不可恢复。"),
      ]),
    ]);
    await ElMessageBox.confirm(message, "确认导入剧本", {
      customClass: "script-import-confirm",
      confirmButtonText: "确认导入",
      cancelButtonText: "取消",
    });
  } catch (error) {
    if (error !== "cancel" && error !== "close") throw error;
    return false;
  }
  return true;
}

async function selectMethod(method: "project" | "local") {
  menuVisible.value = false;
  if (method === "local") {
    selectedFile.value = null;
    localDialogOpen.value = true;
    return;
  }
  selectedProjectId.value = "";
  projectKeyword.value = "";
  projectDialogOpen.value = true;
  loadingProjects.value = true;
  try {
    projects.value = await creativeApi.scriptAnalysisImportProjects();
  } catch (error) {
    showError(error, "加载剧本反推项目失败");
  } finally {
    loadingProjects.value = false;
  }
}

async function importProject() {
  if (!selectedProject.value || processing.value) return;
  if (!(await confirmImport(selectedProject.value.name))) return;
  if (!(await props.beforeImport())) return;
  processing.value = true;
  try {
    const script = await creativeApi.importScriptAnalysisProject(props.scriptId, selectedProjectId.value);
    emit("imported", script);
    projectDialogOpen.value = false;
    toast.success("已导入项目中反推完成的剧本");
  } catch (error) {
    showError(error, "导入剧本失败");
  } finally {
    processing.value = false;
  }
}

function chooseLocalFile() {
  fileInput.value?.click();
}

function selectFile(event: Event) {
  const input = event.target as HTMLInputElement;
  const file = input.files?.[0];
  input.value = "";
  if (!file) return;
  const extension = file.name.toLowerCase().slice(file.name.lastIndexOf("."));
  if (extension !== ".txt" && extension !== ".doc") {
    toast.warning("仅支持 TXT 和 DOC 文件");
    return;
  }
  if (file.size > 3 * 1024 * 1024) {
    toast.warning("剧本文件不能超过 3MB");
    return;
  }
  selectedFile.value = file;
}

async function importFile() {
  const file = selectedFile.value;
  if (!file || processing.value) return;
  if (!(await confirmImport(file.name))) return;
  if (!(await props.beforeImport())) return;
  processing.value = true;
  try {
    const script = await creativeApi.importScriptAnalysisFile(props.scriptId, file);
    emit("imported", script);
    localDialogOpen.value = false;
    toast.success("本地剧本导入成功");
  } catch (error) {
    showError(error, "导入剧本失败");
  } finally {
    processing.value = false;
  }
}

function formatFileSize(size: number) {
  if (size < 1024) return `${size} B`;
  return `${(size / 1024).toFixed(size < 1024 * 100 ? 1 : 0)} KB`;
}
</script>

<template>
  <el-popover
    v-model:visible="menuVisible"
    placement="bottom-start"
    :width="248"
    :show-arrow="false"
    popper-class="script-import-popover"
    trigger="click"
  >
    <template #reference>
      <el-button
        :loading="processing"
        :disabled="disabled"
      >
        <FileInput :size="16" />导入剧本
      </el-button>
    </template>
    <div class="import-menu">
      <button
        type="button"
        class="import-menu__item"
        :disabled="processing"
        @click="selectMethod('project')"
      >
        <FolderInput :size="19" />
        <span><strong>从剧本反推项目导入</strong><small>导入所有已完成的剧集</small></span>
      </button>
      <button
        type="button"
        class="import-menu__item"
        :disabled="processing"
        @click="selectMethod('local')"
      >
        <Upload :size="19" />
        <span><strong>从本地导入</strong><small>支持 TXT、DOC 文件</small></span>
      </button>
    </div>
  </el-popover>

  <el-dialog
    v-model="projectDialogOpen"
    align-center
    title="从剧本反推项目导入"
    width="min(920px, calc(100vw - 28px))"
    class="web-dialog creative-dialog script-import-dialog project-import-dialog"
  >
    <div class="project-import">
      <el-input
        v-model="projectKeyword"
        clearable
        placeholder="搜索项目名称"
        class="project-import__search"
      >
        <template #prefix><Search :size="17" /></template>
      </el-input>
      <div
        v-loading="loadingProjects"
        class="project-import__list"
      >
        <button
          v-for="project in filteredProjects"
          :key="project.id"
          type="button"
          class="project-import__item"
          :class="{ active: selectedProjectId === project.id }"
          :disabled="processing"
          @click="selectedProjectId = project.id"
        >
          <span class="project-import__file"><FileText :size="19" /></span>
          <span class="project-import__content">
            <strong>{{ project.name }}</strong>
            <small>
              已完成 {{ project.episode_count }} 集 · {{ project.char_count }} 字 ·
              {{ formatDateTime(project.updated_at) }}
            </small>
          </span>
        </button>
        <div
          v-if="!loadingProjects && !filteredProjects.length"
          class="project-import__empty"
        >
          <Search
            v-if="projectKeyword.trim()"
            :size="30"
          />
          <FileText
            v-else
            :size="30"
          />
          <strong>{{ projectKeyword.trim() ? "未找到匹配项目" : "暂无可导入的项目" }}</strong>
          <span>{{ projectKeyword.trim() ? "请尝试其他项目名称" : "仅展示至少有一集已完成剧本反推的项目" }}</span>
        </div>
      </div>
    </div>
    <template #footer>
      <el-button @click="projectDialogOpen = false">取消</el-button>
      <el-button
        type="primary"
        :loading="processing"
        :disabled="!selectedProjectId"
        @click="importProject"
      >
        导入所选项目
      </el-button>
    </template>
  </el-dialog>

  <el-dialog
    v-model="localDialogOpen"
    align-center
    title="从本地导入"
    width="min(480px, calc(100vw - 28px))"
    class="web-dialog creative-dialog script-import-dialog local-import-dialog"
  >
    <input
      ref="fileInput"
      class="script-import-file"
      type="file"
      accept=".txt,.doc"
      @change="selectFile"
    />
    <div
      v-loading="processing"
      class="local-import"
    >
      <span class="local-import__icon"><Upload :size="26" /></span>
      <strong>{{ selectedFile ? "已选择剧本文件" : "选择本地剧本文件" }}</strong>
      <div
        v-if="selectedFile"
        class="local-import__selected"
      >
        <FileText :size="18" />
        <span
          ><strong>{{ selectedFile.name }}</strong
          ><small>{{ formatFileSize(selectedFile.size) }}</small></span
        >
      </div>
      <span v-else>支持 TXT、DOC 格式，文件最大 3MB</span>
      <el-button
        :disabled="processing"
        @click="chooseLocalFile"
      >
        {{ selectedFile ? "重新选择" : "选择文件" }}
      </el-button>
    </div>
    <template #footer>
      <el-button @click="localDialogOpen = false">取消</el-button>
      <el-button
        type="primary"
        :loading="processing"
        :disabled="!selectedFile"
        @click="importFile"
      >
        导入文件
      </el-button>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss">
.script-import-file {
  display: none;
}
.import-menu {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.import-menu__item {
  width: 100%;
  min-height: 60px;
  padding: 10px 12px;
  display: flex;
  align-items: center;
  gap: 11px;
  color: var(--web-text);
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}
.import-menu__item:hover {
  background: var(--web-hover);
}
.import-menu__item > svg {
  flex: 0 0 auto;
  color: var(--web-primary);
}
.import-menu__item span,
.project-import__content {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.import-menu__item small,
.project-import__content small,
.project-import__empty span,
.local-import > span:not(.local-import__icon) {
  color: var(--web-muted);
  font-size: 12px;
  line-height: 1.6;
}
.import-menu__item:disabled,
.project-import__item:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.project-import {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.project-import__search {
  width: min(360px, 100%);
}
.project-import__list {
  min-height: 400px;
  height: min(560px, calc(80vh - 190px));
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  gap: 8px;
  overflow-y: auto;
}
.project-import__item {
  width: 100%;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--web-text);
  text-align: left;
  background: var(--web-raised);
  border: 1px solid var(--web-line);
  border-radius: 10px;
  cursor: pointer;
}
.project-import__item:hover,
.project-import__item.active {
  background: var(--web-hover);
  border-color: var(--web-primary);
}
.project-import__file,
.local-import__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  color: var(--web-primary);
  background: color-mix(in srgb, var(--web-primary) 12%, transparent);
  border-radius: 9px;
}
.project-import__file {
  width: 36px;
  height: 36px;
}
.project-import__content strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.project-import__empty {
  min-height: 400px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 8px;
  color: var(--web-muted);
  text-align: center;
  grid-column: 1 / -1;
}
.project-import__empty strong {
  color: var(--web-text);
}
.local-import {
  min-height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  text-align: center;
}
.local-import__icon {
  width: 52px;
  height: 52px;
  margin-bottom: 4px;
}
.local-import__selected {
  width: min(340px, 100%);
  padding: 11px 13px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--web-primary);
  text-align: left;
  background: var(--web-raised);
  border: 1px solid var(--web-line);
  border-radius: 9px;
}
.local-import__selected > span {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.local-import__selected strong {
  overflow: hidden;
  color: var(--web-text);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.local-import__selected small {
  color: var(--web-muted);
  font-size: 12px;
}
:global(.script-import-popover) {
  padding: 6px !important;
}
:global(.project-import-dialog .el-dialog__footer),
:global(.local-import-dialog .el-dialog__footer) {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
:global(.project-import-dialog .el-dialog__footer .el-button),
:global(.local-import-dialog .el-dialog__footer .el-button) {
  margin-left: 0;
}
:global(.script-import-confirm.el-message-box) {
  width: min(440px, calc(100vw - 28px));
  padding: 0;
  background: var(--web-raised);
  border: 1px solid var(--web-line);
  border-radius: 14px;
  box-shadow: 0 22px 60px color-mix(in srgb, var(--web-text) 18%, transparent);
  overflow: hidden;
}
:global(.script-import-confirm .el-message-box__header) {
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--web-line);
}
:global(.script-import-confirm .el-message-box__title) {
  color: var(--web-text);
  font-size: 17px;
  font-weight: 600;
}
:global(.script-import-confirm .el-message-box__content) {
  padding: 20px;
}
:global(.script-import-confirm__content) {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
:global(.script-import-confirm__icon) {
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  flex: 0 0 42px;
  color: var(--web-warning);
  background: color-mix(in srgb, var(--web-warning) 13%, transparent);
  border-radius: 10px;
}
:global(.script-import-confirm__copy) {
  min-width: 0;
}
:global(.script-import-confirm__copy strong) {
  display: block;
  overflow-wrap: anywhere;
  color: var(--web-text);
  font-size: 14px;
}
:global(.script-import-confirm__copy p) {
  margin: 6px 0 0;
  color: var(--web-muted);
  font-size: 13px;
  line-height: 1.65;
}
:global(.script-import-confirm .el-message-box__btns) {
  padding: 0 20px 18px;
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
:global(.script-import-confirm .el-message-box__btns .el-button) {
  margin-left: 0;
}
@media (max-width: 600px) {
  .project-import__list {
    min-height: 360px;
    height: min(500px, calc(80vh - 180px));
    grid-template-columns: 1fr;
  }
  .project-import__item {
    align-items: flex-start;
  }
  .project-import__content small {
    white-space: normal;
  }
  .project-import__empty {
    min-height: 360px;
  }
}
</style>
