<!-- 重绘脚本面板，负责脚本反推任务状态、正文编辑、保存状态和复制操作。 -->
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { CircleClose, Document } from "@element-plus/icons-vue";
import { Copy } from "@/icons";
import type { GenerationTask } from "@/api/creative";
import { taskElapsedLabel } from "@/utils/taskTimeout";
import { useToastStore } from "@/stores/toast";

const props = defineProps<{
  content: string;
  ready: boolean;
  task?: GenerationTask;
  starting?: boolean;
  saving?: boolean;
  saveState?: "idle" | "saved" | "error";
  now?: number;
}>();
const emit = defineEmits<{
  reverse: [];
  stop: [task: GenerationTask];
  "update:content": [content: string];
  save: [];
}>();
const toast = useToastStore();
const editorVisible = ref(Boolean(props.content));
const active = computed(() =>
  Boolean(
    props.task &&
    [
      "pending_submission",
      "submitting",
      "submitted",
      "processing",
      "result_ready",
      "downloading",
      "cancel_requested",
    ].includes(props.task.status),
  ),
);
const stopping = computed(() => props.task?.status === "cancel_requested");
const saveLabel = computed(() =>
  props.saving ? "保存中" : props.saveState === "error" ? "保存失败" : props.saveState === "saved" ? "已保存" : "",
);
const buttonLabel = computed(() =>
  props.starting
    ? "正在启动"
    : stopping.value
      ? "停止中"
      : active.value
        ? `停止反推 ${taskElapsedLabel(props.task!, props.now || Date.now())}`
        : !props.ready
          ? "请先完成所有分镜反推"
          : props.content.trim()
            ? "重新反推为剧本"
            : "反推为剧本",
);
/** 根据当前任务状态触发生成、停止或重新生成操作。 */
function handleAction() {
  if (active.value && props.task) emit("stop", props.task);
  else emit("reverse");
}
/** 更新本地剧本文本并通知父级安排自动保存。 */
function updateContent(value: string) {
  emit("update:content", value);
}
watch(
  () => props.content,
  (content) => {
    if (content) editorVisible.value = true;
  },
);
/** 将反推脚本复制到剪贴板并展示结果提示。 */
async function copyScript() {
  if (!props.content.trim()) return;
  try {
    await navigator.clipboard.writeText(props.content);
    toast.success("剧本已复制");
  } catch {
    toast.error("复制失败，请检查浏览器剪贴板权限");
  }
}
</script>

<template>
  <section class="redraw-column script-column">
    <header>
      <strong>剧本</strong><small v-if="editorVisible">{{ content.length }} 字</small>
      <small
        v-if="saveLabel"
        class="script-save-state"
        :class="{ 'is-error': saveState === 'error' }"
        >{{ saveLabel }}</small
      >
      <button
        v-if="content"
        type="button"
        class="script-copy-button"
        title="复制剧本"
        @click="copyScript"
      >
        <Copy :size="15" />
        <span>复制</span>
      </button>
    </header>
    <div class="script-body">
      <el-input
        v-if="editorVisible"
        :model-value="content"
        type="textarea"
        resize="none"
        :disabled="active"
        @update:model-value="updateContent"
        @blur="$emit('save')"
      />
      <div
        v-else
        class="script-empty"
      >
        <el-icon><Document /></el-icon>
        <strong>{{ active ? "正在反推完整剧本" : "尚未反推剧本" }}</strong>
        <span>{{ ready ? "全部分镜提示词已就绪，可以开始反推。" : "请先完成所有分镜反推。" }}</span>
      </div>
      <el-button
        class="script-action-button"
        :class="{ 'is-unready': !active && !ready }"
        :type="active ? 'danger' : 'primary'"
        :icon="active ? CircleClose : Document"
        :loading="starting"
        :disabled="starting || stopping || (!active && !ready)"
        @click="handleAction"
        >{{ buttonLabel }}</el-button
      >
    </div>
  </section>
</template>

<style scoped lang="scss">
.script-column {
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.script-copy-button {
  min-height: 28px;
  margin-left: auto;
  padding: 0 9px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--web-accent-muted);
  background: var(--web-surface);
  border: 1px solid var(--web-line-strong);
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
  transition:
    color 0.16s,
    background-color 0.16s,
    border-color 0.16s;
}
.script-save-state {
  color: var(--web-text-disabled);
}
.script-save-state.is-error {
  color: var(--el-color-danger);
}
.script-copy-button:hover {
  color: var(--web-text);
  background: var(--web-hover);
  border-color: var(--web-scrollbar-global-thumb);
}
.script-body {
  min-height: 0;
  padding: 12px;
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 10px;
}
.script-body :deep(.el-textarea),
.script-body :deep(.el-textarea__inner) {
  min-height: 0;
  height: 100%;
  flex: 1;
}
.script-body :deep(.el-textarea__inner) {
  padding: 12px;
  color: var(--web-text-secondary);
  line-height: 1.75;
  background: var(--web-surface-soft);
  box-shadow: 0 0 0 1px var(--web-line-strong) inset;
}
.script-empty {
  min-height: 260px;
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 9px;
  color: var(--web-script-hint);
  text-align: center;
}
.script-empty .el-icon {
  color: var(--web-accent-dark);
  font-size: 30px;
}
.script-empty strong {
  color: var(--web-text-secondary);
  font-size: 14px;
}
.script-empty span {
  max-width: 240px;
  font-size: 12px;
  line-height: 1.6;
}
.script-action-button.is-unready,
.script-action-button.is-unready:hover {
  color: var(--web-text-disabled);
  background: var(--web-surface-soft);
  border-color: var(--web-line-strong);
  opacity: 1;
  cursor: not-allowed;
}
</style>
