// @vitest-environment happy-dom

import { createPinia, setActivePinia } from 'pinia';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { useUserStore } from '@easyflow/stores';

import {
  allocateAgentComposerSession,
  deleteAgentComposerDraft,
  getAgentComposerDraft,
  saveAgentComposerDraft,
} from './mediaApi';
import { useAgentComposerDraft } from './useAgentComposerDraft';

vi.mock('./mediaApi', () => ({
  allocateAgentComposerSession: vi.fn(),
  deleteAgentChatImage: vi.fn(),
  deleteAgentComposerDraft: vi.fn(),
  getAgentComposerDraft: vi.fn(),
  loadAgentChatImage: vi.fn(),
  saveAgentComposerDraft: vi.fn(),
  uploadAgentChatImage: vi.fn(),
}));

describe('useAgentComposerDraft', () => {
  beforeEach(() => {
    setActivePinia(createPinia());
    useUserStore().setUserInfo({
      avatar: '',
      id: 'user-1',
      loginName: 'admin',
      nickname: '管理员',
      tenantId: 'tenant-1',
    });
    localStorage.clear();
    vi.clearAllMocks();
    vi.mocked(allocateAgentComposerSession).mockResolvedValue({
      data: { mode: 'FORMAL', sessionId: '100' },
      errorCode: 0,
    });
    vi.mocked(getAgentComposerDraft).mockResolvedValue({
      data: null,
      errorCode: 0,
    });
    vi.mocked(deleteAgentComposerDraft).mockResolvedValue({
      data: undefined,
      errorCode: 0,
    });
    vi.mocked(saveAgentComposerDraft).mockImplementation(async (draft) => ({
      data: {
        ...draft,
        expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
        revision: draft.revision + 1,
      },
      errorCode: 0,
    }));
  });

  it('restores an unsynced local shadow and writes it back to Redis', async () => {
    vi.useFakeTimers();
    const first = useAgentComposerDraft('FORMAL');
    await first.activate('agent-1');
    first.text.value = '刷新前尚未发送的内容';
    first.scheduleSave();

    const restored = useAgentComposerDraft('FORMAL');
    await restored.activate('agent-1');

    expect(restored.sessionId.value).toBe('100');
    expect(restored.text.value).toBe('刷新前尚未发送的内容');
    expect(saveAgentComposerDraft).toHaveBeenCalledWith(
      expect.objectContaining({
        agentId: 'agent-1',
        sessionId: '100',
        text: '刷新前尚未发送的内容',
      }),
    );
    vi.useRealTimers();
  });

  it('keeps local shadows isolated by the logged-in account', async () => {
    vi.useFakeTimers();
    const first = useAgentComposerDraft('FORMAL');
    await first.activate('agent-1');
    first.text.value = '账号一的草稿';
    first.scheduleSave();

    useUserStore().setUserInfo({
      avatar: '',
      id: 'user-2',
      loginName: 'other',
      nickname: '其他用户',
      tenantId: 'tenant-1',
    });
    vi.mocked(allocateAgentComposerSession).mockResolvedValueOnce({
      data: { mode: 'FORMAL', sessionId: '200' },
      errorCode: 0,
    });
    const second = useAgentComposerDraft('FORMAL');
    await second.activate('agent-1');

    expect(second.sessionId.value).toBe('200');
    expect(second.text.value).toBe('');
    vi.useRealTimers();
  });

  it('serializes a debounced save and the send-time flush', async () => {
    vi.useFakeTimers();
    let resolveFirstSave: (() => void) | undefined;
    vi.mocked(saveAgentComposerDraft).mockImplementation((draft) => {
      if (!resolveFirstSave) {
        return new Promise((resolve) => {
          resolveFirstSave = () =>
            resolve({
              data: { ...draft, revision: 1 },
              errorCode: 0,
            });
        });
      }
      return Promise.resolve({
        data: { ...draft, revision: draft.revision + 1 },
        errorCode: 0,
      });
    });
    const composer = useAgentComposerDraft('FORMAL');
    await composer.activate('agent-1');
    composer.text.value = '并发保存内容';
    composer.scheduleSave();
    await vi.advanceTimersByTimeAsync(500);
    await Promise.resolve();

    const flushPromise = composer.flush();
    await Promise.resolve();
    expect(saveAgentComposerDraft).toHaveBeenCalledTimes(1);

    resolveFirstSave?.();
    await flushPromise;

    expect(saveAgentComposerDraft).toHaveBeenCalledTimes(2);
    expect(saveAgentComposerDraft).toHaveBeenLastCalledWith(
      expect.objectContaining({ revision: 1, text: '并发保存内容' }),
    );
    vi.useRealTimers();
  });

  it('waits for an in-flight save before clearing an accepted draft', async () => {
    vi.useFakeTimers();
    let resolveSave: (() => void) | undefined;
    vi.mocked(saveAgentComposerDraft).mockImplementation(
      (draft) =>
        new Promise((resolve) => {
          resolveSave = () =>
            resolve({
              data: { ...draft, revision: 1 },
              errorCode: 0,
            });
        }),
    );
    const composer = useAgentComposerDraft('DRAFT');
    await composer.activate('agent-1', 'agent-draft-100');
    composer.text.value = '试运行内容';
    composer.scheduleSave();
    await vi.advanceTimersByTimeAsync(500);
    await Promise.resolve();

    const accepted = composer.markAccepted();
    await Promise.resolve();
    expect(deleteAgentComposerDraft).not.toHaveBeenCalled();

    resolveSave?.();
    await accepted;

    expect(deleteAgentComposerDraft).toHaveBeenCalledWith({
      agentId: 'agent-1',
      deleteUploads: false,
      imageUploadIds: [],
      mode: 'DRAFT',
      sessionId: 'agent-draft-100',
    });
    expect(composer.text.value).toBe('');
    vi.useRealTimers();
  });
});
