import type { WebCanvasWorkflow, WebCanvasWorkflowNodePackage } from "../../types";
import type { AssetLibraryCategory } from "../assets/localAssetStore";
import type {
  CanvasImageNode,
  CanvasManualLink,
  CanvasNodeKind,
  CanvasNodePackage,
  CanvasNodeSize,
  CanvasSelectedNode,
  CanvasTextNode,
  CanvasVideoNode,
} from "./canvasTypes";
import {
  assetLibraryCategories,
  canvasNodeDefaultSizes,
  defaultTextModelId,
  imageRatioOptions,
  videoRatioOptions,
} from "./canvasConstants";
import {
  clampCanvasNodeSize,
  getCanvasSelectionKey,
  getWorkflowImageNodeFileName,
  getWorkflowImageNodePrompt,
  getWorkflowNodeFocusSelection,
  getWorkflowNodeMetadataString,
  getWorkflowNodeStyleReference,
  resolveImageQuality,
  resolveVideoQuality,
  resolveWorkflowImageModel,
  resolveWorkflowRatio,
  resolveWorkflowVideoMode,
  resolveWorkflowVideoModel,
} from "./canvasUtils";

export function resolveAssetCategory(value: string): AssetLibraryCategory {
  return assetLibraryCategories.find((category) => category.key === value || category.label === value)?.key || "prop";
}

export function getWorkflowNodeCanvasKind(node: WebCanvasWorkflow["nodes"][number]): CanvasNodeKind {
  if (node.kind === "image") return "image";
  if (node.kind === "video") return "video";
  return "text";
}

export function getWorkflowNodeSize(node: WebCanvasWorkflow["nodes"][number], kind: CanvasNodeKind): CanvasNodeSize {
  return clampCanvasNodeSize(
    kind,
    Number(node.size?.width) || canvasNodeDefaultSizes[kind].width,
    Number(node.size?.height) || canvasNodeDefaultSizes[kind].height,
  );
}

export function createTextNodesFromWorkflow(workflow: WebCanvasWorkflow): CanvasTextNode[] {
  return workflow.nodes
    .filter((node) => getWorkflowNodeCanvasKind(node) === "text")
    .map((node, index) => ({
      id: node.id || `workflow-text-${index + 1}`,
      title: node.label || `文本节点 ${index + 1}`,
      prompt: node.kind === "prompt" ? node.detail : "",
      content: node.kind === "prompt" ? "" : node.detail,
      isEditingContent: false,
      isComposerOpen: node.kind === "prompt" && !node.detail,
      selectedModelId: defaultTextModelId,
      position: { ...node.position },
      size: getWorkflowNodeSize(node, "text"),
    }));
}

export function createImageNodesFromWorkflow(workflow: WebCanvasWorkflow): CanvasImageNode[] {
  return workflow.nodes
    .filter((node) => getWorkflowNodeCanvasKind(node) === "image")
    .map((node, index) => {
      const model = resolveWorkflowImageModel(node, workflow.settings.model);
      const aspectRatio = resolveWorkflowRatio(node, workflow.settings.ratio, imageRatioOptions, "16:9");
      const imageSize = resolveImageQuality(
        model,
        getWorkflowNodeMetadataString(node, "imageSize", workflow.settings.resolution || "2K"),
      );
      return {
      id: node.id || `workflow-image-${index + 1}`,
      title: node.label || `图片节点 ${index + 1}`,
      prompt: getWorkflowImageNodePrompt(node),
      imageUrl: node.assetRef?.url || node.previewUrl || "",
      model,
      aspectRatio,
      imageSize,
      assetRef: node.assetRef || null,
      taskRef: node.taskRef || null,
      styleReference: getWorkflowNodeStyleReference(node),
      focusSelection: getWorkflowNodeFocusSelection(node),
      marking: getWorkflowNodeMetadataString(node, "marking", ""),
      fileName: getWorkflowImageNodeFileName(node, index),
      position: { ...node.position },
      size: getWorkflowNodeSize(node, "image"),
      };
    });
}

export function createVideoNodesFromWorkflow(workflow: WebCanvasWorkflow): CanvasVideoNode[] {
  return workflow.nodes
    .filter((node) => getWorkflowNodeCanvasKind(node) === "video")
    .map((node, index) => {
      const model = resolveWorkflowVideoModel(node, workflow.settings.model);
      const aspectRatio = resolveWorkflowRatio(node, workflow.settings.ratio, videoRatioOptions, "16:9");
      const resolution = resolveVideoQuality(
        model,
        getWorkflowNodeMetadataString(node, "resolution", workflow.settings.resolution || "720p"),
      );
      return {
      id: node.id || `workflow-video-${index + 1}`,
      title: node.label || `视频节点 ${index + 1}`,
      prompt: node.detail || "",
      videoUrl: node.assetRef?.url || node.previewUrl || "",
      model,
      aspectRatio,
      resolution,
      duration: getWorkflowNodeMetadataString(node, "duration", String(workflow.settings.duration || "4")).replace(/s$/i, ""),
      videoMode: resolveWorkflowVideoMode(node),
      marking: getWorkflowNodeMetadataString(node, "marking", ""),
      cameraMotion: getWorkflowNodeMetadataString(node, "cameraMotion", ""),
      assetRef: node.assetRef || null,
      taskRef: node.taskRef || null,
      sourceTextNodeId: "",
      position: { ...node.position },
      size: getWorkflowNodeSize(node, "video"),
      };
    });
}

export function createManualLinksFromWorkflow(workflow: WebCanvasWorkflow): CanvasManualLink[] {
  const kindById = new Map<string, CanvasNodeKind>(
    workflow.nodes.map((node) => [node.id, getWorkflowNodeCanvasKind(node)]),
  );

  return workflow.edges.flatMap((edge, index) => {
    const sourceKind = kindById.get(edge.source);
    const targetKind = kindById.get(edge.target);
    if (!sourceKind || !targetKind || edge.source === edge.target) return [];
    return [
      {
        id: edge.id || `workflow-link-${index + 1}`,
        from: { kind: sourceKind, nodeId: edge.source, side: "right", slot: "center" },
        to: { kind: targetKind, nodeId: edge.target, side: "left", slot: "center" },
      },
    ];
  });
}

export function createNodePackagesFromWorkflow(workflow: WebCanvasWorkflow): CanvasNodePackage[] {
  const nodeKindById = new Map<string, CanvasNodeKind>(
    workflow.nodes.map((node) => [node.id, getWorkflowNodeCanvasKind(node)]),
  );

  return (workflow.packages || []).flatMap((nodePackage, index) => {
    const uniqueNodeKeys = new Set<string>();
    const packageNodeIds = Array.isArray(nodePackage.nodeIds) ? nodePackage.nodeIds : [];
    const nodeIds = packageNodeIds.reduce<CanvasSelectedNode[]>((items, node) => {
      const kind = node.kind || nodeKindById.get(node.id);
      if ((kind !== "text" && kind !== "image" && kind !== "video") || !nodeKindById.has(node.id)) return items;
      const key = getCanvasSelectionKey({ kind, id: node.id });
      if (uniqueNodeKeys.has(key)) return items;
      uniqueNodeKeys.add(key);
      items.push({ kind, id: node.id });
      return items;
    }, []);
    if (nodeIds.length < 2) return [];

    return [
      {
        id: nodePackage.id || `canvas-node-package-${index + 1}`,
        title: nodePackage.title || `打包节点 ${index + 1}`,
        nodeIds,
        collapsed: nodePackage.collapsed === true,
        collapsedBounds: nodePackage.collapsedBounds || undefined,
        updatedAt: nodePackage.updatedAt,
      },
    ];
  });
}

export function createWorkflowPackagesFromCanvasPackages(
  nodePackages: CanvasNodePackage[],
): WebCanvasWorkflowNodePackage[] {
  return nodePackages.map((nodePackage) => ({
    id: nodePackage.id,
    title: nodePackage.title,
    nodeIds: nodePackage.nodeIds.map((node) => ({ kind: node.kind, id: node.id })),
    collapsed: nodePackage.collapsed === true,
    collapsedBounds: nodePackage.collapsedBounds || null,
    updatedAt: nodePackage.updatedAt,
  }));
}

export function formatCanvasProjectUpdatedAt(updatedAt: string) {
  const date = new Date(updatedAt);
  if (Number.isNaN(date.getTime())) return "最近更新";

  const diffMinutes = Math.max(0, Math.floor((Date.now() - date.getTime()) / 60000));
  if (diffMinutes < 1) return "刚刚更新";
  if (diffMinutes < 60) return `${diffMinutes} 分钟前`;

  const diffHours = Math.floor(diffMinutes / 60);
  if (diffHours < 24) return `${diffHours} 小时前`;

  const diffDays = Math.floor(diffHours / 24);
  if (diffDays < 7) return `${diffDays} 天前`;

  return date.toLocaleDateString("zh-CN", {
    month: "2-digit",
    day: "2-digit",
  });
}

export function formatCanvasVideoTime(value: number) {
  if (!Number.isFinite(value) || value <= 0) return "0:00";
  const totalSeconds = Math.floor(value);
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;
  return `${minutes}:${String(seconds).padStart(2, "0")}`;
}
