import { create } from 'zustand';
import type { GenerationTask, ReferenceSnapshot, UploadedFile, BackendTask } from '../types';
import { useInputBarStore } from './inputBar';
import { videoApi, mediaApi } from '../lib/api';
import { useAuthStore } from './auth';
import { showToast } from '../components/Toast';

// Map raw API error messages to user-friendly Chinese
function mapErrorMessage(raw?: string): string | undefined {
  if (!raw) return undefined;
  const s = raw.toLowerCase();

  // HTTP 4xx
  if (s.includes('400') || s.includes('bad request') || s.includes('invalid'))
    return '请求参数有误，请检查输入内容';
  if (s.includes('401') || s.includes('403') || s.includes('unauthorized') || s.includes('forbidden'))
    return '服务认证失败，请联系管理员';
  if (s.includes('429') || s.includes('too many') || s.includes('rate limit'))
    return '请求过于频繁，请稍后再试';

  // HTTP 5xx / server errors
  if (s.includes('500') || s.includes('502') || s.includes('503') || s.includes('internal server') || s.includes('bad gateway') || s.includes('service unavailable'))
    return '服务器繁忙，请稍后重试';

  // Timeout
  if (s.includes('timeout') || s.includes('timed out'))
    return '请求超时，请重试';

  // Connection errors
  if (s.includes('connection') || s.includes('network') || s.includes('econnrefused'))
    return '网络连接失败，请检查网络后重试';

  // Model / generation errors
  if (s.includes('quota') || s.includes('insufficient'))
    return '今日生成次数或团队余额不足，请联系管理员';

  // If already Chinese, return as-is
  if (/[\u4e00-\u9fa5]/.test(raw)) return raw;

  // Fallback
  return '生成失败，请重试';
}

// Map backend status to frontend TaskStatus
function mapStatus(backendStatus: string): 'generating' | 'completed' | 'failed' {
  if (backendStatus === 'completed' || backendStatus === 'succeeded') return 'completed';
  if (backendStatus === 'failed') return 'failed';
  return 'generating';
}

function mapProgress(backendStatus: string): number {
  if (backendStatus === 'completed') return 100;
  if (backendStatus === 'failed') return 0;
  return 50;
}

/** Check if a URL is an asset library reference (case-insensitive protocol). */
function isAssetUrl(url: string): boolean {
  return url.startsWith('asset://') || url.startsWith('Asset://');
}

/** Build ReferenceSnapshot[] from raw reference_urls (including asset refs with thumb_url). */
function buildReferenceSnapshots(
  refs: Array<Record<string, string>>,
  taskId: string,
): ReferenceSnapshot[] {
  return refs
    .filter((ref) => {
      const url = ref.url || '';
      // 素材库引用必须有 thumb_url 才能显示缩略图
      if (isAssetUrl(url)) return !!(ref.thumb_url);
      return url.trim() !== '';
    })
    .map((ref, i) => {
      const url = ref.url || '';
      const assetRef = isAssetUrl(url);
      return {
        id: `ref_${taskId}_${i}`,
        type: (ref.type || 'image') as 'image' | 'video' | 'audio',
        // 素材库引用用 thumb_url，直接上传用原始 url
        previewUrl: assetRef ? ref.thumb_url : url,
        label: ref.label || `素材${i + 1}`,
        role: ref.role,
        isAssetRef: assetRef || undefined,
      };
    });
}

/** Extract asset mention metadata from raw reference_urls. */
function buildAssetMentions(refs: Array<Record<string, string>>) {
  return refs
    .filter((ref) => isAssetUrl(ref.url || ''))
    .map((ref) => {
      const url = ref.url || '';
      // New format: asset://local-{id}
      if (url.startsWith('asset://local-')) {
        const assetId = url.replace('asset://local-', '');
        return {
          assetId, label: ref.label || '', thumbUrl: ref.thumb_url || '',
          assetType: ref.type || 'image', duration: parseFloat(ref.duration || '0'),
        };
      }
      // Legacy format: asset://group-{id}
      const groupId = url.startsWith('asset://group-') ? url.replace('asset://group-', '') : '';
      return { groupId, label: ref.label || '', thumbUrl: ref.thumb_url || '', assetType: 'image', duration: 0 };
    });
}

// Convert a BackendTask to a frontend GenerationTask
function backendToFrontend(bt: BackendTask): GenerationTask {
  const allRefs = bt.reference_urls || [];
  const references = buildReferenceSnapshots(allRefs, bt.task_id);
  const assetMentions = buildAssetMentions(allRefs);

  return {
    id: `backend_${bt.task_id}`,
    taskId: bt.task_id,
    prompt: bt.prompt,
    editorHtml: bt.prompt,
    mode: bt.mode,
    model: bt.model,
    aspectRatio: bt.aspect_ratio as GenerationTask['aspectRatio'],
    duration: bt.duration as GenerationTask['duration'],
    resolution: bt.resolution,
    references,
    assetMentions,
    status: mapStatus(bt.status),
    progress: bt.status === 'processing' ? Number(sessionStorage.getItem(`progress_${bt.task_id}`) || mapProgress(bt.status)) : mapProgress(bt.status),
    resultUrl: bt.result_url || undefined,
    thumbnailUrl: bt.thumbnail_url || undefined,
    errorMessage: mapErrorMessage(bt.error_message),
    createdAt: new Date(bt.created_at).getTime(),
    tokensConsumed: bt.tokens_consumed || 0,
    costAmount: bt.cost_amount || 0,
    isFavorited: bt.is_favorited || false,
    seed: bt.seed ?? -1,
  };
}

// Active polling timers
const pollTimers = new Map<string, ReturnType<typeof setTimeout>>();

// Smooth progress animation — continuously ticks generating tasks forward
let smoothProgressTimer: ReturnType<typeof setInterval> | null = null;

function ensureSmoothProgress() {
  if (smoothProgressTimer) return;
  smoothProgressTimer = setInterval(() => {
    const state = useGenerationStore.getState();
    const generating = state.tasks.filter((t) => t.status === 'generating');
    if (generating.length === 0) {
      clearInterval(smoothProgressTimer!);
      smoothProgressTimer = null;
      return;
    }
    useGenerationStore.setState((s) => ({
      tasks: s.tasks.map((t) => {
        if (t.status !== 'generating') return t;
        // Decelerate: fast at start, slow near end
        const increment = t.progress < 30 ? 2 : t.progress < 60 ? 1 : 0.5;
        const newProgress = Math.min(t.progress + increment, 95);
        if (t.taskId) sessionStorage.setItem(`progress_${t.taskId}`, String(newProgress));
        return { ...t, progress: newProgress };
      }),
    }));
  }, 2000);
}

// Progressive polling: 10s for first 2min, 30s for 2-5min, 60s after 5min
function getPollingInterval(startTime: number): number {
  const elapsed = Date.now() - startTime;
  if (elapsed < 2 * 60 * 1000) return 10 * 1000;      // first 2 min: every 10s
  if (elapsed < 5 * 60 * 1000) return 30 * 1000;       // 2-5 min: every 30s
  return 60 * 1000;                                      // 5+ min: every 60s
}

function startPolling(taskId: string, frontendId: string) {
  if (pollTimers.has(frontendId)) return;

  const startTime = Date.now();

  function schedulePoll() {
    const timer = setTimeout(async () => {
      try {
        const { data } = await videoApi.getTaskStatus(taskId);
        const newStatus = mapStatus(data.status);

        // Parse references from polling response
        const pollAllRefs = data.reference_urls || [];
        const pollRefs = buildReferenceSnapshots(pollAllRefs, taskId);
        const pollAssetMentions = buildAssetMentions(pollAllRefs);

        useGenerationStore.setState((s) => ({
          tasks: s.tasks.map((t) =>
            t.id === frontendId
              ? {
                  ...t,
                  status: newStatus,
                  progress: newStatus === 'completed' ? 100 : newStatus === 'failed' ? 0 : t.progress,
                  resultUrl: data.result_url || t.resultUrl,
                  errorMessage: mapErrorMessage(data.error_message) || t.errorMessage,
                  tokensConsumed: data.tokens_consumed ?? t.tokensConsumed,
                  costAmount: data.cost_amount ?? t.costAmount,
                  seed: data.seed ?? t.seed,
                  references: pollRefs.length > 0 ? pollRefs : t.references,
                  assetMentions: pollAssetMentions.length > 0 ? pollAssetMentions : t.assetMentions,
                }
              : t
          ),
        }));

        if (newStatus === 'completed' || newStatus === 'failed') {
          pollTimers.delete(frontendId);
          sessionStorage.removeItem(`progress_${taskId}`);
          if (newStatus === 'completed') {
            useAuthStore.getState().fetchUserInfo();
          }
        } else {
          schedulePoll(); // schedule next poll with progressive interval
        }
      } catch {
        schedulePoll(); // retry on error
      }
    }, getPollingInterval(startTime));

    pollTimers.set(frontendId, timer);
  }

  schedulePoll();
}

function stopPolling(frontendId: string) {
  const timer = pollTimers.get(frontendId);
  if (timer) {
    clearTimeout(timer);
    pollTimers.delete(frontendId);
  }
}

const PAGE_SIZE = 20;

interface GenerationState {
  tasks: GenerationTask[];
  isLoading: boolean;
  isLoadingMore: boolean;
  hasMore: boolean;
  savedScrollTop: number | null;
  addTask: () => Promise<string | null>;
  removeTask: (id: string) => void;
  toggleFavorite: (id: string) => Promise<void>;
  reEdit: (id: string) => void;
  regenerate: (id: string) => void;
  loadTasks: () => Promise<void>;
  loadMore: () => Promise<void>;
  saveScrollPosition: (top: number) => void;
}

export const useGenerationStore = create<GenerationState>((set, get) => ({
  tasks: [],
  isLoading: false,
  isLoadingMore: false,
  hasMore: false,
  savedScrollTop: null,

  loadTasks: async () => {
    set({ isLoading: true });

    let tasks: GenerationTask[] = [];
    let hasMore = false;

    try {
      const { data } = await videoApi.getTasks({ page_size: PAGE_SIZE, offset: 0 });
      tasks = data.results.map(backendToFrontend).reverse();
      hasMore = data.has_more;
    } catch {
      // API unavailable — tasks stays empty
    }

    set({ tasks, hasMore, isLoading: false });

    // Start polling and smooth progress for any active tasks
    let hasGenerating = false;
    for (const task of tasks) {
      if (task.status === 'generating' && task.taskId) {
        startPolling(task.taskId, task.id);
        hasGenerating = true;
      }
    }
    if (hasGenerating) ensureSmoothProgress();
  },

  loadMore: async () => {
    const { tasks, isLoadingMore, hasMore } = get();
    if (isLoadingMore || !hasMore) return;

    set({ isLoadingMore: true });

    try {
      // Backend returns newest-first; we display oldest-first (reversed).
      // tasks[0] is the oldest currently loaded. We need older ones = higher offset.
      // offset = total loaded from backend perspective
      const currentBackendCount = tasks.filter((t) => !t.id.startsWith('temp_')).length;
      const { data } = await videoApi.getTasks({ page_size: PAGE_SIZE, offset: currentBackendCount });
      const olderTasks = data.results.map(backendToFrontend).reverse();
      set((s) => ({
        tasks: [...olderTasks, ...s.tasks],
        hasMore: data.has_more,
        isLoadingMore: false,
      }));
    } catch {
      set({ isLoadingMore: false });
    }
  },

  addTask: async () => {
    const input = useInputBarStore.getState();
    if (!input.canSubmit()) return null;

    // Collect files to upload (or existing TOS URLs for regeneration)
    const filesToUpload: { file?: File; tosUrl?: string; type: 'image' | 'video' | 'audio'; role: string; label: string }[] = [];

    const getRoleForType = (type: 'image' | 'video' | 'audio') =>
      type === 'video' ? 'reference_video' : type === 'audio' ? 'reference_audio' : 'reference_image';

    if (input.mode === 'universal') {
      for (const ref of input.references) {
        if (ref.tosUrl) {
          filesToUpload.push({ tosUrl: ref.tosUrl, type: ref.type, role: getRoleForType(ref.type), label: ref.label });
        } else if (ref.file) {
          filesToUpload.push({ file: ref.file, type: ref.type, role: getRoleForType(ref.type), label: ref.label });
        }
      }
    } else {
      if (input.firstFrame?.tosUrl) {
        filesToUpload.push({ tosUrl: input.firstFrame.tosUrl, type: 'image', role: 'first_frame', label: '首帧' });
      } else if (input.firstFrame?.file) {
        filesToUpload.push({ file: input.firstFrame.file, type: 'image', role: 'first_frame', label: '首帧' });
      }
      if (input.lastFrame?.tosUrl) {
        filesToUpload.push({ tosUrl: input.lastFrame.tosUrl, type: 'image', role: 'last_frame', label: '尾帧' });
      } else if (input.lastFrame?.file) {
        filesToUpload.push({ file: input.lastFrame.file, type: 'image', role: 'last_frame', label: '尾帧' });
      }
    }

    // Snapshot references for local display before uploading
    const localRefs: ReferenceSnapshot[] =
      input.mode === 'universal'
        ? input.references.map((r) => ({
            id: r.id,
            type: r.type,
            previewUrl: r.previewUrl,
            label: r.label,
          }))
        : [
            input.firstFrame && {
              id: input.firstFrame.id,
              type: input.firstFrame.type,
              previewUrl: input.firstFrame.previewUrl,
              label: '首帧',
            },
            input.lastFrame && {
              id: input.lastFrame.id,
              type: input.lastFrame.type,
              previewUrl: input.lastFrame.previewUrl,
              label: '尾帧',
            },
          ].filter(Boolean) as ReferenceSnapshot[];

    // Extract asset mentions for placeholder display
    const placeholderAssetMentions: Record<string, unknown>[] = [];
    if (input.editorHtml) {
      const parser = new DOMParser();
      const doc = parser.parseFromString(input.editorHtml, 'text/html');
      const spans = doc.querySelectorAll('[data-ref-type="asset"]');
      const seen = new Set<string>();
      spans.forEach((span) => {
        const el = span as HTMLElement;
        const gid = el.dataset.assetGroupId;
        if (gid && !seen.has(gid)) {
          seen.add(gid);
          placeholderAssetMentions.push({
            groupId: gid,
            label: el.dataset.groupName || el.textContent?.replace('@', '') || '',
            thumbUrl: el.dataset.thumbUrl || '',
          });
        }
      });
    }
    // Fallback: from inputBar store (regenerate 场景 editorHtml 是纯文本)
    if (placeholderAssetMentions.length === 0 && input.assetMentions?.length) {
      placeholderAssetMentions.push(...input.assetMentions);
    }

    // Create a placeholder task immediately for UI feedback
    const tempId = `temp_${Date.now()}`;
    const placeholderTask: GenerationTask = {
      id: tempId,
      taskId: '',
      prompt: input.prompt,
      editorHtml: input.editorHtml,
      mode: input.mode,
      model: input.model,
      aspectRatio: input.aspectRatio,
      duration: input.duration,
      resolution: input.resolution,
      references: localRefs,
      assetMentions: placeholderAssetMentions,
      status: 'generating',
      progress: 0,
      createdAt: Date.now(),
      isFavorited: false,
      seed: input.seed ?? -1,
    };

    set((s) => ({ tasks: [...s.tasks, placeholderTask] }));

    // Start smooth progress animation
    ensureSmoothProgress();

    // Clear input
    useInputBarStore.setState({
      prompt: '',
      editorHtml: '',
      references: [],
      assetMentions: [],
      firstFrame: null,
      lastFrame: null,
    });

    try {
      // Use pre-uploaded TOS URLs (immediate upload), fallback to upload here if needed
      const uploadedRefs: { url: string; type: string; role: string; label: string; thumb_url?: string; duration?: string }[] = [];

      for (const item of filesToUpload) {
        if (item.tosUrl && !item.tosUrl.startsWith('blob:')) {
          uploadedRefs.push({ url: item.tosUrl, type: item.type, role: item.role, label: item.label });
        } else if (item.file) {
          // Fallback: file wasn't pre-uploaded (shouldn't normally happen with immediate upload)
          const { data: uploadResult } = await mediaApi.upload(item.file);
          uploadedRefs.push({ url: uploadResult.url, type: item.type, role: item.role, label: item.label });
        }
      }

      // Extract asset mentions from editor HTML — deduplicate by assetId
      const seenAssetIds = new Set<string>();
      if (input.editorHtml) {
        const parser = new DOMParser();
        const doc = parser.parseFromString(input.editorHtml, 'text/html');
        const assetSpans = doc.querySelectorAll('[data-ref-type="asset"]');
        assetSpans.forEach((span) => {
          const el = span as HTMLElement;
          const assetId = el.dataset.assetId;
          const assetType = (el.dataset.assetType || 'Image').toLowerCase();
          const assetName = el.dataset.assetName || el.textContent?.replace('@', '') || '';
          const duration = el.dataset.duration || '0';
          if (assetId && !seenAssetIds.has(assetId)) {
            seenAssetIds.add(assetId);
            uploadedRefs.push({
              url: `asset://local-${assetId}`,
              type: assetType,
              role: `reference_${assetType}`,
              label: assetName,
              thumb_url: el.dataset.thumbUrl || '',
              duration,
            });
          }
          // Legacy: data-asset-group-id (old format)
          if (!assetId && el.dataset.assetGroupId) {
            const groupId = el.dataset.assetGroupId;
            const groupName = el.dataset.groupName || el.textContent?.replace('@', '') || '';
            if (!seenAssetIds.has(`group-${groupId}`)) {
              seenAssetIds.add(`group-${groupId}`);
              uploadedRefs.push({
                url: `asset://group-${groupId}`,
                type: 'image',
                role: 'reference_image',
                label: groupName,
                thumb_url: el.dataset.thumbUrl || '',
              });
            }
          }
        });
      }

      // Fallback: only use inputBar assetMentions when editorHtml has NO asset spans
      // (regenerate scenario where editorHtml is plain text)
      const htmlHadAssetSpans = input.editorHtml?.includes('data-ref-type="asset"');
      if (!htmlHadAssetSpans) {
        const inputAssetMentions = input.assetMentions || [];
        for (const am of inputAssetMentions) {
          // New format
          if (am.assetId && !seenAssetIds.has(am.assetId)) {
            seenAssetIds.add(am.assetId);
            const t = (am.assetType || 'Image').toLowerCase();
            uploadedRefs.push({
              url: `asset://local-${am.assetId}`,
              type: t,
              role: `reference_${t}`,
              label: am.label,
              thumb_url: am.thumbUrl || '',
              duration: String(am.duration || 0),
            });
          }
          // Legacy format
          if (!am.assetId && am.groupId && !seenAssetIds.has(`group-${am.groupId}`)) {
            seenAssetIds.add(`group-${am.groupId}`);
            uploadedRefs.push({
              url: `asset://group-${am.groupId}`,
              type: 'image',
              role: 'reference_image',
              label: am.label,
              thumb_url: am.thumbUrl || '',
            });
          }
        }
      }

      // Call generate API
      const { data: genResult } = await videoApi.generate({
        prompt: input.prompt,
        mode: input.mode,
        model: input.model,
        aspect_ratio: input.aspectRatio,
        duration: input.duration,
        resolution: input.resolution,
        references: uploadedRefs,
        search_mode: input.searchMode || 'off',
        seed: input.seed ?? -1,
      });

      // Update task with real backend IDs
      const frontendId = `backend_${genResult.task_id}`;
      const taskStatus = mapStatus(genResult.status);
      set((s) => ({
        tasks: s.tasks.map((t) =>
          t.id === tempId
            ? {
                ...t,
                id: frontendId,
                taskId: genResult.task_id,
                status: taskStatus as GenerationTask['status'],
                progress: taskStatus === 'completed' ? 100 : taskStatus === 'failed' ? 0 : t.progress,
                errorMessage: mapErrorMessage(genResult.error_message) || t.errorMessage,
              }
            : t
        ),
      }));

      // Update reference previews with TOS URLs (persist on refresh)
      const updatedRefs = localRefs.map((ref, i) => ({
        ...ref,
        previewUrl: uploadedRefs[i]?.url || ref.previewUrl,
      }));
      set((s) => ({
        tasks: s.tasks.map((t) =>
          t.id === frontendId ? { ...t, references: updatedRefs } : t
        ),
      }));

      // Start polling only if task is still generating
      if (taskStatus === 'generating') {
        startPolling(genResult.task_id, frontendId);
      }

      // Refresh quota
      useAuthStore.getState().fetchUserInfo();

      return frontendId;
    } catch (err: unknown) {
      const error = err as { response?: { status?: number; data?: { message?: string; error_message?: string } } };
      const msg = error.response?.data?.error_message || error.response?.data?.message || '生成失败，请重试';
      const displayMsg = mapErrorMessage(msg) || msg;
      showToast(displayMsg);

      // Mark task as failed with error message
      set((s) => ({
        tasks: s.tasks.map((t) =>
          t.id === tempId ? { ...t, status: 'failed' as const, progress: 0, errorMessage: displayMsg } : t
        ),
      }));

      return null;
    }
  },

  removeTask: (id) => {
    stopPolling(id);
    const task = get().tasks.find((t) => t.id === id);
    set((s) => ({ tasks: s.tasks.filter((t) => t.id !== id) }));
    if (task?.taskId) {
      videoApi.deleteTask(task.taskId).catch(() => {});
    }
  },

  toggleFavorite: async (id) => {
    const task = get().tasks.find((t) => t.id === id);
    if (!task?.taskId) return;
    // Optimistic update
    set((s) => ({
      tasks: s.tasks.map((t) => t.id === id ? { ...t, isFavorited: !t.isFavorited } : t),
    }));
    try {
      await videoApi.toggleFavorite(task.taskId);
    } catch {
      // Revert on failure
      set((s) => ({
        tasks: s.tasks.map((t) => t.id === id ? { ...t, isFavorited: !t.isFavorited } : t),
      }));
    }
  },

  reEdit: (id) => {
    const task = get().tasks.find((t) => t.id === id);
    if (!task) return;

    const inputStore = useInputBarStore.getState();

    if (inputStore.mode !== task.mode) {
      inputStore.switchMode(task.mode);
    }

    if (task.mode === 'universal') {
      // Only include direct file refs — asset library refs are tracked via assetMentions
      const references: UploadedFile[] = task.references
        .filter((r) => !r.isAssetRef)
        .map((r) => ({
          id: r.id,
          type: r.type,
          previewUrl: r.previewUrl,
          label: r.label,
          tosUrl: r.previewUrl,
        }));

      // Always use plain text prompt for reEdit — let PromptInput's rebuildMentionSpans
      // reconstruct tags from references + assetMentions (avoids dead blob: URLs)
      const taskSeed = task.seed ?? -1;
      const currentSeedEnabled = useInputBarStore.getState().seedEnabled;
      useInputBarStore.setState({
        prompt: task.prompt,
        editorHtml: task.prompt,
        aspectRatio: task.aspectRatio,
        duration: task.duration,
        resolution: task.resolution,
        references,
        assetMentions: task.assetMentions || [],
        // 如果 seed 开关打开且 task 有有效 seed，填入；否则不动
        ...(currentSeedEnabled && taskSeed > 0 ? { seed: taskSeed } : {}),
      });
    } else {
      // Keyframe mode: restore firstFrame and lastFrame
      const firstRef = task.references.find((r) => r.label === '首帧');
      const lastRef = task.references.find((r) => r.label === '尾帧');
      useInputBarStore.setState({
        prompt: task.prompt,
        editorHtml: task.editorHtml || task.prompt,
        aspectRatio: task.aspectRatio,
        duration: task.duration,
        resolution: task.resolution,
        assetMentions: [],
        firstFrame: firstRef ? { id: firstRef.id, type: firstRef.type, previewUrl: firstRef.previewUrl, label: '首帧', tosUrl: firstRef.previewUrl } : null,
        lastFrame: lastRef ? { id: lastRef.id, type: lastRef.type, previewUrl: lastRef.previewUrl, label: '尾帧', tosUrl: lastRef.previewUrl } : null,
      });
    }
  },

  regenerate: (id) => {
    const task = get().tasks.find((t) => t.id === id);
    if (!task) return;

    // Restore task data into input bar and trigger addTask
    const inputStore = useInputBarStore.getState();

    if (inputStore.mode !== task.mode) {
      inputStore.switchMode(task.mode);
    }

    // For regeneration, we need to re-submit with the same TOS URLs
    // Only include direct file refs — asset library refs go via assetMentions fallback
    const references: UploadedFile[] = task.references
      .filter((r) => !r.isAssetRef)
      .map((r) => ({
        id: r.id,
        type: r.type,
        previewUrl: r.previewUrl,
        label: r.label,
        tosUrl: r.previewUrl,
      }));

    useInputBarStore.setState({
      prompt: task.prompt,
      editorHtml: task.editorHtml || task.prompt,
      model: task.model,
      aspectRatio: task.aspectRatio,
      duration: task.duration,
      resolution: task.resolution,
      references: task.mode === 'universal' ? references : [],
      assetMentions: task.assetMentions || [],
    });

    // Trigger generation
    get().addTask();
  },

  saveScrollPosition: (top: number) => {
    set({ savedScrollTop: top });
  },
}));
