import { isServerRequestError } from "../../api/serverConnection";
import { ENTERPRISE_VIDEO_MODEL_OPTIONS } from "../../utils/enterpriseVideoPolicy";
import type { WebGenerationPreviewTask } from "../../types";
import type { GenerationLifecycleStatus, TaskRefundStatus, TextTokenUsage } from "../../utils/taskLifecycle";
import type { ReactNode } from "react";

export type WorkbenchMode = "chat" | "image" | "video";
export type ToolbarMenuId =
  | "studio-mode"
  | "chat-model"
  | "chat-speed"
  | "chat-depth"
  | "image-model"
  | "image-settings"
  | "image-grid-mode"
  | "video-model"
  | "video-mode"
  | "video-ratio"
  | "video-duration"
  | "video-quality"
  | null;
export type ReferenceKind = "image" | "video" | "audio" | "file";

export interface WorkbenchOption {
  value: string;
  label: string;
  description?: string;
  badge?: string;
}

export interface WorkbenchFieldGroup {
  label: string;
  value: string;
  options: WorkbenchOption[];
  onChange: (value: string) => void;
  kind?: "ratio" | "pill";
  columns?: 2 | 3 | 4;
  icon?: ReactNode;
}

export interface ReferenceItem {
  id: string;
  kind: ReferenceKind;
  name: string;
  previewUrl?: string;
  file?: File;
  remoteUrl?: string;
  token: string;
  fingerprint?: string;
  originalSize?: number;
  compressed?: boolean;
}

export type PromptMentionItem = Pick<ReferenceItem, "token" | "id" | "name" | "kind" | "previewUrl" | "remoteUrl">;

export interface PromptMentionTokenRange {
  start: number;
  end: number;
  item: PromptMentionItem;
}

export interface ChatAttachment {
  kind: ReferenceKind;
  name: string;
  token: string;
  previewUrl?: string;
  remoteUrl?: string;
}

export interface ChatMessage {
  id: string;
  role: "user" | "assistant";
  author: string;
  mode: WorkbenchMode;
  body: string;
  prompt?: string;
  createdAt: string;
  status?: "thinking" | "queued" | "completed" | "failed" | "stopping" | "local_timeout";
  taskLifecycleStatus?: GenerationLifecycleStatus;
  taskRefundStatus?: TaskRefundStatus;
  taskUsage?: TextTokenUsage;
  taskId?: string;
  conversationId?: number;
  taskProgress?: number;
  taskStatusLabel?: string;
  attachments?: ChatAttachment[];
  resultUrl?: string;
  resultType?: "image" | "video";
  resultOriginalUrl?: string;
  resultOssKey?: string;
  resultMimeType?: string;
  result?: {
    title: string;
    summary: string;
    specs: string[];
  };
}

export interface DeleteDialogState {
  projectId: string;
  title: string;
}

export interface WorkbenchKeepaliveTask {
  taskId: string;
  conversationId: number;
  assistantMessageId: string;
  concurrencySlotId?: string;
  operation?: "generation" | "video-super-resolution";
  mode: "image" | "video";
  modelLabel: string;
  specs: string[];
  referenceCount: number;
  progress: number;
  statusLabel: string;
  startedAt: number;
}

export interface WorkbenchResultActionPayload {
  title: string;
  prompt: string;
  resultUrl: string;
  resultType: "image" | "video";
  taskId?: string;
  resultOriginalUrl?: string;
  resultOssKey?: string;
  resultMimeType?: string;
}

// ─── Constants ───────────────────────────────────────────────────────

export const MESSAGE_STORAGE_KEY = "omniai-web-workbench-messages";
export const ACTIVE_CONVERSATION_STORAGE_KEY = "omniai-web-workbench-active-conversation-id";
export const PROMPT_HISTORY_STORAGE_KEY = "omniai-web-workbench-prompt-history";
export const TASK_KEEPALIVE_STORAGE_KEY = "omniai-web-workbench-active-tasks";
export const WORKBENCH_TASK_STALE_MS = 6 * 60 * 60 * 1000;
export const WORKBENCH_TASK_MAX_POLL_FAILURES = 10;
export const REFERENCE_IMAGE_COMPRESS_THRESHOLD = 10 * 1024 * 1024;
export const REFERENCE_IMAGE_MAX_DIMENSION = 1920;
export const REFERENCE_IMAGE_INITIAL_QUALITY = 0.84;
export const REFERENCE_IMAGE_MIN_QUALITY = 0.62;
export const CHAT_MODEL = "gemini-3.1-pro";

export const CHAT_MODEL_OPTIONS: WorkbenchOption[] = [
  { value: "gemini", label: "Gemini" },
  { value: "wanxian", label: "万相" },
  { value: "deepseek", label: "DeepSeek" },
];

export const THINKING_SPEED_OPTIONS: WorkbenchOption[] = [
  { value: "default", label: "默认" },
  { value: "high", label: "思考速度：高" },
  { value: "ultra", label: "思考速度：急速" },
];

export const THINKING_DEPTH_OPTIONS: WorkbenchOption[] = [
  { value: "default", label: "默认" },
  { value: "strong", label: "推理深度：强" },
  { value: "extreme", label: "推理深度：极限" },
];

export const CHAT_NATURAL_SYSTEM_PROMPT = [
  "你是 OmniAI 的创作协作助手，像一个正在一起工作的同伴一样说话。",
  `默认使用自然、简洁的中文，不要官腔，不要机械套话，不要频繁使用“首先、其次、最后”这种模板。`,
  "先直接回应用户当前关心的点；需要拆解时，用短段落或少量要点，把下一步说清楚。",
  `不说“作为一个 AI”，不做空泛总结，不编造不确定的信息。`,
  "当用户在排查问题或调整页面时，优先给判断、原因和可执行的下一步。",
].join("\n");

export const CHAT_TURN_STYLE_REMINDER = [
  "本轮回答继续保持像正常人协作的口吻：",
  `不要以"好的，以下是""当然可以""根据你的需求"这类模板开头。`,
  "能一句话说清就先一句话说清；需要展开时再分点。",
  "少用宏大标题，多用具体判断和下一步动作。",
].join("\n");

export const NON_CONVERSATIONAL_ASSISTANT_TEXT = new Set([
  "我先看一下上下文，马上接上。",
  "我在整理，马上说清楚。",
  "正在读取当前模式、模型、规格和参考素材，准备创建生成任务。",
  "Task submitted, generating...",
  "任务已提交，正在生成中...",
  "AI 正在整理回答...",
]);

export const MODE_META: Record<
  WorkbenchMode,
  {
    label: string;
    menuLabel: string;
    accent: string;
    placeholder: string;
    description: string;
    subline: string;
    taskType: WebGenerationPreviewTask["type"];
  }
> = {
  chat: {
    label: "OmniChat",
    menuLabel: "对话模式",
    accent: "#6be7ff",
    placeholder: "把创意、脚本、素材要求或工作流目标发给我",
    description: "直接对话、拆解需求、整理上下文，并把想法推进到可执行结果。",
    subline: "适合连续协作、问答推演、脚本整理和工作流规划。",
    taskType: "agent",
  },
  image: {
    label: "图像生成",
    menuLabel: "图像生成",
    accent: "#00b1cc",
    placeholder: "描述角色、场景、商品图、首帧或尾帧画面",
    description: "在同一界面完成文生图、图生图、参考图管理和候选筛选。",
    subline: "模型、比例、清晰度和多宫格保持在同一条工作链里。",
    taskType: "image",
  },
  video: {
    label: "视频生成",
    menuLabel: "视频生成",
    accent: "#2197ff",
    placeholder: "描述成片目标、人物、场景、镜头运动、节奏、比例和时长",
    description: "用统一工作台管理起始帧、动作描述、镜头节奏和视频输出。",
    subline: "支持首尾帧、参考素材、比例、时长和画质等关键设置。",
    taskType: "video",
  },
};

export const MODE_OPTIONS: WorkbenchOption[] = (Object.keys(MODE_META) as WorkbenchMode[]).map((mode) => ({
  value: mode,
  label: MODE_META[mode].menuLabel,
  description: MODE_META[mode].subline,
}));

export const IMAGE_MODEL_OPTIONS: WorkbenchOption[] = [
  { value: "wan2.7-image-pro", label: "wan 2.7 Pro" },
  { value: "wan2.7-image", label: "wan 2.7" },
  { value: "gpt-image-2", label: "omni-GPT" },
  { value: "gpt-image-2-vip", label: "omni-GPT VIP" },
  { value: "nano-banana-pro", label: "omni-水果 Pro" },
  { value: "nano-banana-2", label: "omni-水果 2" },
  { value: "nano-banana-fast", label: "omni-水果" },
];

export const VIDEO_MODEL_OPTIONS: WorkbenchOption[] = ENTERPRISE_VIDEO_MODEL_OPTIONS.map((option) => ({ ...option }));
export const RATIO_OPTIONS: WorkbenchOption[] = [
  { value: "21:9", label: "21:9" },
  { value: "16:9", label: "16:9" },
  { value: "4:3", label: "4:3" },
  { value: "1:1", label: "1:1" },
  { value: "3:4", label: "3:4" },
  { value: "9:16", label: "9:16" },
];

export const GRID_MODE_OPTIONS: WorkbenchOption[] = [
  { value: "single", label: "单图" },
  { value: "grid-4", label: "4 宫格" },
  { value: "grid-9", label: "9 宫格" },
  { value: "grid-25", label: "25 宫格" },
];

export const GRID_SUPPORTED_MODELS = new Set([
  "wan2.7-image-pro",
  "wan2.7-image",
  "gpt-image-2",
  "gpt-image-2-vip",
]);

export const VIDEO_FRAME_OPTIONS: WorkbenchOption[] = [
  { value: "omni", label: "全能参考" },
  { value: "start-end", label: "首尾帧" },
];

export const VIDEO_DURATION_OPTIONS: WorkbenchOption[] = [
  { value: "5", label: "5s" },
  { value: "6", label: "6s" },
  { value: "7", label: "7s" },
  { value: "8", label: "8s" },
  { value: "9", label: "9s" },
  { value: "10", label: "10s" },
  { value: "11", label: "11s" },
  { value: "12", label: "12s" },
  { value: "13", label: "13s" },
  { value: "14", label: "14s" },
  { value: "15", label: "15s" },
];

// ─── Shared helpers ──────────────────────────────────────────────────

export function getCachedRole(): string {
  try {
    const raw = window.localStorage.getItem("omniai-web-session");
    if (!raw) return "";
    return String(JSON.parse(raw)?.user?.role || "").trim().toLowerCase();
  } catch { return ""; }
}

export function getSessionUserId(): string {
  try {
    const raw = window.localStorage.getItem("omniai-web-session");
    if (!raw) return "anon";
    const id = JSON.parse(raw)?.user?.id;
    return id ? String(id) : "anon";
  } catch { return "anon"; }
}

export function userKey(base: string): string {
  return `${base}:${getSessionUserId()}`;
}

export function createId(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}

export function formatWorkbenchTimestamp(date = new Date()): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  const hours = String(date.getHours()).padStart(2, "0");
  const minutes = String(date.getMinutes()).padStart(2, "0");
  return `${year}-${month}-${day} ${hours}:${minutes}`;
}

export function parseWorkbenchTimestampValue(value: string): number {
  const matched = value.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})/);
  if (matched) {
    const [, year, month, day, hours, minutes] = matched;
    return new Date(Number(year), Number(month) - 1, Number(day), Number(hours), Number(minutes)).getTime();
  }
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) ? parsed : NaN;
}

export function buildChatAttachments(items: ReferenceItem[]): ChatAttachment[] {
  return items.map((item) => ({
    kind: item.kind,
    name: item.name,
    token: item.token,
    previewUrl: item.remoteUrl || item.previewUrl,
    remoteUrl: item.remoteUrl,
  }));
}

export function buildNaturalChatHistoryMessages(messages: ChatMessage[]): Array<{ role: "user" | "assistant"; content: string }> {
  return messages
    .filter((message) => {
      const body = message.body.trim();
      if (!body) return false;
      if (message.role === "user") return true;
      if (message.mode !== "chat") return false;
      if (message.status === "thinking" || message.status === "queued") return false;
      if (NON_CONVERSATIONAL_ASSISTANT_TEXT.has(body)) return false;
      return true;
    })
    .slice(-10)
    .map((message) => ({
      role: message.role,
      content: message.body.trim(),
    }));
}

export function getErrorText(error: unknown): string {
  return error instanceof Error ? error.message : String(error || "Unknown error");
}

export function isAuthFailure(error: unknown): boolean {
  return isServerRequestError(error) && (error.status === 401 || error.status === 403);
}

export function isInsufficientBalance(error: unknown): boolean {
  if (isServerRequestError(error) && error.status === 402) return true;
  const msg = error instanceof Error ? error.message : String(error || "");
  return /余额不足|积分不足|insufficient.?balance/i.test(msg);
}

export function isInsufficientBalanceMessage(msg: string | undefined | null): boolean {
  if (!msg) return false;
  return /余额不足|积分不足|insufficient.?balance/i.test(msg);
}

export function isTransientMessage(message: ChatMessage): boolean {
  return (message.status === "thinking" || message.status === "queued") && !message.taskId;
}

export function getPersistableMessages(messages: ChatMessage[]): ChatMessage[] {
  return messages.filter((message, index) => {
    if (isTransientMessage(message)) return false;
    if (message.role === "assistant") return true;
    const nextMessage = messages[index + 1];
    return (
      nextMessage?.role === "assistant" &&
      nextMessage.conversationId === message.conversationId &&
      !isTransientMessage(nextMessage)
    );
  });
}

export function shouldPersistPatch(patch: Partial<ChatMessage>): boolean {
  return (
    patch.status === "completed" ||
    patch.status === "failed" ||
    patch.status === "local_timeout" ||
    patch.status === "stopping" ||
    typeof patch.taskId === "string" ||
    typeof patch.resultUrl === "string" ||
    typeof patch.resultOssKey === "string" ||
    typeof patch.resultOriginalUrl === "string" ||
    typeof patch.resultMimeType === "string" ||
    typeof patch.taskRefundStatus === "string" ||
    typeof patch.taskLifecycleStatus === "string" ||
    typeof patch.taskUsage === "object"
  );
}

export function buildAssistantResult(
  mode: WorkbenchMode,
  model: string,
  specs: string[],
  referenceCount: number,
): ChatMessage["result"] {
  if (mode === "image") {
    return {
      title: "图像任务已创建",
      summary: referenceCount > 0 ? "已携带参考图，后续结果会进入资产库和画布。" : "已按当前模型和规格进入图像生成流程。",
      specs,
    };
  }

  if (mode === "video") {
    return {
      title: "视频任务已创建",
      summary: referenceCount > 0 ? "已携带参考素材，生成后可继续拆分镜头并发布案例。" : "已按当前镜头设置进入视频生成流程。",
      specs,
    };
  }

  return {
    title: "Agent 已接管",
    summary: "我会把当前输入整理成脚本、分镜、素材需求和可复制的工作流节点。",
    specs: [model, ...specs],
  };
}
