import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { act, cleanup, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import type { ReactNode } from "react";
import { MemoryRouter } from "react-router-dom";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

vi.mock("./lib/api", () => ({
  cancelJdQrLogin: vi.fn(),
  cancelTmallQrLogin: vi.fn(),
  clearJdManagedSession: vi.fn(),
  clearJdSessionManagerConfig: vi.fn(),
  clearPlatformSession: vi.fn(),
  clearTmallManagedSession: vi.fn(),
  clearTmallSessionManagerConfig: vi.fn(),
  confirmTask: vi.fn(),
  createTask: vi.fn(),
  createTaskEventsSource: vi.fn(() => ({
    addEventListener: vi.fn(),
    close: vi.fn(),
    removeEventListener: vi.fn()
  })),
  deleteTask: vi.fn(),
  getJdKeywordPreview: vi.fn(),
  getJdLiveSession: vi.fn(),
  getJdQrLoginState: vi.fn(),
  getJdSessionManager: vi.fn(),
  getHistoryTasks: vi.fn(),
  getPlatformReadiness: vi.fn(),
  getPlatformSession: vi.fn(),
  getTask: vi.fn(),
  getTaskCandidates: vi.fn(),
  getTaskReport: vi.fn(),
  getTmallLiveSession: vi.fn(),
  getTmallQrLoginState: vi.fn(),
  getTmallSessionManager: vi.fn(),
  importJdManagedSession: vi.fn(),
  importTmallManagedSession: vi.fn(),
  preparePlatform: vi.fn(),
  resumeJdQrLoginManualRecovery: vi.fn(),
  runJdSessionManagerHealthCheck: vi.fn(),
  runJdSessionManagerRecovery: vi.fn(),
  runTmallSessionManagerHealthCheck: vi.fn(),
  retryTaskPlatform: vi.fn(),
  startJdQrLogin: vi.fn(),
  startTmallQrLogin: vi.fn(),
  updateJdSessionManagerConfig: vi.fn(),
  updateTmallSessionManagerConfig: vi.fn()
}));

import { App, NewTaskPage } from "./App";
import {
  cancelJdQrLogin,
  cancelTmallQrLogin,
  clearJdManagedSession,
  clearPlatformSession,
  clearTmallManagedSession,
  getJdKeywordPreview,
  getJdLiveSession,
  getJdQrLoginState,
  getJdSessionManager,
  getHistoryTasks,
  getPlatformReadiness,
  getPlatformSession,
  getTask,
  getTaskCandidates,
  getTmallLiveSession,
  getTmallQrLoginState,
  getTmallSessionManager,
  importJdManagedSession,
  importTmallManagedSession,
  preparePlatform,
  createTaskEventsSource,
  runJdSessionManagerHealthCheck,
  runJdSessionManagerRecovery,
  runTmallSessionManagerHealthCheck,
  startJdQrLogin,
  startTmallQrLogin,
  updateJdSessionManagerConfig
} from "./lib/api";

function renderWithProviders(node: ReactNode, initialEntries?: string[]) {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        retry: false
      }
    }
  });

  return render(
    <QueryClientProvider client={queryClient}>
      {initialEntries ? (
        <MemoryRouter initialEntries={initialEntries}>{node}</MemoryRouter>
      ) : (
        <MemoryRouter>{node}</MemoryRouter>
      )}
    </QueryClientProvider>
  );
}

describe("task composer and session console", () => {
  beforeEach(() => {
    const jdManagerState = {
      status: "healthy",
      enabled: true,
      autoLoginMode: "command",
      commandConfigured: true,
      accountConfigured: true,
      passwordConfigured: false,
      accountLabel: "jd***86",
      browserProfilePath: "D:\\ops\\jd-profile",
      heartbeatQuery: "iPhone 15",
      checkIntervalMs: 600000,
      runnerTimeoutMs: 300000,
      pendingManualAction: false,
      note: "京东会话当前可用。",
      publicNote: "京东会话由运维后台维护，当前可用。",
      configuredAt: "2026-04-02T08:00:00.000Z",
      lastCheckAt: "2026-04-02T10:00:00.000Z",
      lastRecoveredAt: "2026-04-02T09:00:00.000Z",
      session: {
        configured: true,
        importedAt: "2026-04-02T10:00:00.000Z",
        hasCookie: true,
        userAgent: "stub-user-agent",
        searchApiTemplate: {
          available: true
        },
        detailTemplate: {
          available: true,
          skuId: "100068388533"
        },
        reviewsTemplate: {
          available: true,
          skuId: "100068388533"
        }
      }
    };
    const tmallManagerState = {
      status: "healthy",
      enabled: true,
      heartbeatItemId: "934454505228",
      checkIntervalMs: 600000,
      pendingManualAction: false,
      note: "天猫会话当前可用。",
      publicNote: "天猫会话由运维后台维护，当前可用。",
      configuredAt: "2026-04-02T08:00:00.000Z",
      lastCheckAt: "2026-04-02T10:00:00.000Z",
      lastHealthyAt: "2026-04-02T10:00:00.000Z",
      session: {
        configured: true,
        importedAt: "2026-04-02T10:00:00.000Z",
        hasCookie: true,
        userAgent: "stub-user-agent",
        detailTemplate: {
          available: true,
          itemId: "934454505228"
        },
        reviewsTemplate: {
          available: true,
          itemId: "934454505228"
        }
      }
    };

    vi.mocked(getPlatformReadiness).mockResolvedValue({
      platforms: [
        {
          platform: "tmall",
          ready: true,
          status: "ready",
          searchRequirement: "recommended",
          reason: "当前工作区存在可复用会话，创建任务时会再次校验。",
          lastPreparedAt: "2026-04-02T12:00:00.000Z",
          expiresAt: "2026-04-03T12:00:00.000Z"
        },
        {
          platform: "jd",
          ready: false,
          status: "missing",
          searchRequirement: "required",
          reason: "需要先完成会话准备，否则系统会标记为 SearchBlocked。"
        }
      ]
    } as any);
    vi.mocked(getHistoryTasks).mockResolvedValue({
      tasks: [
        {
          taskId: "task-1",
          query: "Nintendo Switch 2",
          taskStatus: "Completed",
          updatedAt: "2026-04-02T12:00:00.000Z",
          hasReport: true,
          defaultReportVersion: 2,
          failedPlatforms: [],
          blockedPlatforms: []
        },
        {
          taskId: "task-2",
          query: "DJI Pocket 3",
          taskStatus: "AwaitingConfirmation",
          updatedAt: "2026-04-02T11:30:00.000Z",
          hasReport: false,
          failedPlatforms: [],
          blockedPlatforms: ["jd"]
        }
      ]
    } as any);
    vi.mocked(getPlatformSession).mockResolvedValue({
      session: {
        platform: "tmall",
        ready: true,
        status: "ready",
        searchRequirement: "recommended",
        scope: "workspace",
        ttlHours: 24,
        lastPreparedAt: "2026-04-02T10:00:00.000Z",
        expiresAt: "2026-04-03T10:00:00.000Z",
        encryptedSnapshotAvailable: true,
        cipherLabel: "mock-aes-gcm-v1"
      }
    } as any);
    vi.mocked(getJdLiveSession).mockResolvedValue({
      session: {
        configured: true,
        importedAt: "2026-04-02T10:00:00.000Z",
        hasCookie: true,
        userAgent: "stub-user-agent",
        searchApiTemplate: {
          available: false
        },
        detailTemplate: {
          available: true,
          skuId: "100068388533"
        },
        reviewsTemplate: {
          available: true,
          skuId: "100068388533"
        }
      }
    } as any);
    vi.mocked(getJdQrLoginState).mockResolvedValue({
      qrLogin: {
        platform: "jd",
        status: "idle",
        note: "尚未启动扫码登录。",
        sessionImported: false
      }
    } as any);
    vi.mocked(getJdKeywordPreview).mockResolvedValue({
      preview: {
        query: "小米手环10",
        search: {
          source: "html",
          candidateCount: 2,
          selected: {
            skuId: "222222222222",
            score: 168,
            summary: "标题完整命中关键词；位于搜索结果前列；已解析出可回放 SKU",
            matchedTokens: ["小米手环10"],
            candidate: {
              candidateId: "jd-222222222222",
              platform: "jd",
              title: "小米手环10 标准版 智能手环",
              price: 269,
              priceLabel: "¥269",
              storeName: "小米京东自营旗舰店",
              productUrl: "https://item.jd.com/222222222222.html",
              imageUrl: "https://img14.360buyimg.com/n2/jfs/t1/example-10.jpg",
              salesHint: "已售50万+",
              specLabel: "标准版",
              highlights: ["14天续航"]
            }
          },
          alternatives: [
            {
              skuId: "111111111111",
              score: 118,
              summary: "标题/卖点命中 1 个关键词片段；已解析出可回放 SKU",
              matchedTokens: ["小米"],
              candidate: {
                candidateId: "jd-111111111111",
                platform: "jd",
                title: "小米手环9 NFC版",
                price: 249,
                priceLabel: "¥249",
                storeName: "小米京东自营旗舰店",
                productUrl: "https://item.jd.com/111111111111.html",
                imageUrl: "https://img14.360buyimg.com/n2/jfs/t1/example-9.jpg",
                salesHint: "已售20万+",
                specLabel: "NFC版",
                highlights: ["健康监测"]
              }
            }
          ]
        },
        product: {
          skuId: "222222222222",
          source: "api",
          detail: {
            skuId: "222222222222",
            title: "小米手环10 标准版 智能手环",
            price: "269.00",
            originalPrice: "299.00",
            estimatedPrice: "269.00",
            shopName: "小米京东自营旗舰店",
            vendorId: null,
            categoryPath: ["智能设备", "智能手环"],
            stockState: "现货",
            mainImage: "https://img14.360buyimg.com/n2/jfs/t1/example-10.jpg",
            averageScore: "4.9"
          },
          pagination: {
            requestedPage: 1,
            requestedCommentCount: 12,
            maxPages: 2,
            pagesFetched: 2,
            pageKey: "page"
          },
          reviews: {
            skuId: "222222222222",
            total: "10000+",
            goodRate: "97%",
            pictureCount: "800",
            tags: [
              {
                tagId: "tag-1",
                name: "续航很久",
                count: "5300"
              }
            ],
            comments: [
              {
                id: "comment-1",
                content: "表带舒适，睡眠监测比较准。",
                score: "5",
                creationTime: "2026-04-03 09:00:00",
                userLevelName: "PLUS会员"
              }
            ]
          }
        }
      }
    } as any);
    vi.mocked(getJdSessionManager).mockResolvedValue({
      manager: jdManagerState
    } as any);
    vi.mocked(getTmallSessionManager).mockResolvedValue({
      manager: tmallManagerState
    } as any);
    vi.mocked(getTmallLiveSession).mockResolvedValue({
      session: tmallManagerState.session
    } as any);
    vi.mocked(getTmallQrLoginState).mockResolvedValue({
      qrLogin: {
        platform: "tmall",
        status: "idle",
        note: "尚未启动扫码登录。",
        sessionImported: false
      }
    } as any);
    vi.mocked(clearPlatformSession).mockResolvedValue(undefined);
    vi.mocked(importJdManagedSession).mockResolvedValue({
      manager: {
        ...jdManagerState,
        note: "京东会话已更新。",
        lastRecoveredAt: "2026-04-02T10:05:00.000Z",
        session: {
          ...jdManagerState.session,
          importedAt: "2026-04-02T10:05:00.000Z",
        }
      }
    } as any);
    vi.mocked(importTmallManagedSession).mockResolvedValue({
      manager: {
        ...tmallManagerState,
        note: "天猫会话已更新。",
        lastHealthyAt: "2026-04-02T10:05:00.000Z",
        session: {
          ...tmallManagerState.session,
          importedAt: "2026-04-02T10:05:00.000Z"
        }
      }
    } as any);
    vi.mocked(clearJdManagedSession).mockResolvedValue({
      manager: {
        status: "idle",
        enabled: true,
        autoLoginMode: "command",
        commandConfigured: true,
        accountConfigured: true,
        passwordConfigured: false,
        accountLabel: "jd***86",
        heartbeatQuery: "iPhone 15",
        checkIntervalMs: 600000,
        runnerTimeoutMs: 300000,
        pendingManualAction: false,
        note: "京东会话已清理。",
        publicNote: "京东会话由运维后台维护，当前尚未就绪。",
        session: {
          configured: false,
          hasCookie: false,
          searchApiTemplate: {
            available: false
          },
          detailTemplate: {
            available: false
          },
          reviewsTemplate: {
            available: false
          }
        }
      }
    } as any);
    vi.mocked(clearTmallManagedSession).mockResolvedValue({
      manager: {
        status: "idle",
        enabled: true,
        heartbeatItemId: "934454505228",
        checkIntervalMs: 600000,
        pendingManualAction: false,
        note: "天猫会话已清理。",
        publicNote: "天猫会话由运维后台维护，当前尚未就绪。",
        session: {
          configured: false,
          hasCookie: false,
          detailTemplate: {
            available: false
          },
          reviewsTemplate: {
            available: false
          }
        }
      }
    } as any);
    vi.mocked(updateJdSessionManagerConfig).mockResolvedValue({
      manager: jdManagerState
    } as any);
    vi.mocked(runJdSessionManagerHealthCheck).mockResolvedValue({
      state: jdManagerState,
      recovered: false
    } as any);
    vi.mocked(runJdSessionManagerRecovery).mockResolvedValue({
      state: jdManagerState,
      recovered: true
    } as any);
    vi.mocked(startJdQrLogin).mockResolvedValue({
      qrLogin: {
        platform: "jd",
        status: "waiting_for_scan",
        note: "二维码已生成，请扫码。",
        targetId: "100068388533",
        qrImageDataUrl: "data:image/png;base64,stub",
        sessionImported: false
      }
    } as any);
    vi.mocked(cancelJdQrLogin).mockResolvedValue({
      qrLogin: {
        platform: "jd",
        status: "cancelled",
        note: "扫码已取消。",
        sessionImported: false
      }
    } as any);
    vi.mocked(runTmallSessionManagerHealthCheck).mockResolvedValue({
      state: tmallManagerState,
      recovered: false
    } as any);
    vi.mocked(startTmallQrLogin).mockResolvedValue({
      qrLogin: {
        platform: "tmall",
        status: "waiting_for_scan",
        note: "二维码已生成，请扫码。",
        targetId: "934454505228",
        qrImageDataUrl: "data:image/png;base64,stub",
        sessionImported: false
      }
    } as any);
    vi.mocked(cancelTmallQrLogin).mockResolvedValue({
      qrLogin: {
        platform: "tmall",
        status: "cancelled",
        note: "扫码已取消。",
        sessionImported: false
      }
    } as any);
    vi.mocked(preparePlatform).mockResolvedValue({
      platform: "jd",
      session_ready: true,
      status: "ready",
      last_prepared_at: "2026-04-02T10:00:00.000Z",
      expires_at: "2026-04-03T10:00:00.000Z",
      encrypted_snapshot_available: true
    } as any);
  });

  afterEach(() => {
    cleanup();
    vi.clearAllMocks();
  });

  it("shows readiness details and recent task shortcuts on the new task page", async () => {
    renderWithProviders(<NewTaskPage />);

    expect(await screen.findByText("最近任务捷径")).toBeInTheDocument();
    expect(await screen.findByText("Nintendo Switch 2")).toBeInTheDocument();
    expect(await screen.findByText("DJI Pocket 3")).toBeInTheDocument();
    expect(await screen.findByText("搜索要求：建议预热")).toBeInTheDocument();
    expect(
      await screen.findByText(/当前工作区已有可复用会话，有效至/)
    ).toBeInTheDocument();
  });

  it("runs the jd keyword-only preview loop from the new task page", async () => {
    const user = userEvent.setup();

    renderWithProviders(<NewTaskPage />);

    await user.clear(await screen.findByLabelText("商品关键词 / 描述"));
    await user.type(screen.getByLabelText("商品关键词 / 描述"), "小米手环10");
    await user.click(screen.getByRole("button", { name: "只用关键词抓京东" }));

    await waitFor(() => {
      expect(getJdKeywordPreview).toHaveBeenCalledWith("小米手环10", {
        commentCount: 12,
        maxPages: 2
      });
    });

    expect(await screen.findByText("小米手环10 标准版 智能手环")).toBeInTheDocument();
    expect(await screen.findByText(/SKU 222222222222/)).toBeInTheDocument();
    expect(await screen.findByText("好评率 97%")).toBeInTheDocument();
    expect(await screen.findByText("表带舒适，睡眠监测比较准。")).toBeInTheDocument();
  });

  it("redirects the tmall prepare route to the unified ops page and clears the managed session", async () => {
    const user = userEvent.setup();

    renderWithProviders(<App />, ["/ops/platforms/tmall/prepare?from=/tasks/new"]);

    await user.click(screen.getByRole("button", { name: "清理当前会话" }));

    await waitFor(() => {
      expect(clearTmallManagedSession).toHaveBeenCalled();
    });
  });

  it("redirects the legacy jd prepare route to the ops session manager page", async () => {
    renderWithProviders(<App />, ["/sessions/jd/prepare?from=/tasks/new"]);

    expect(await screen.findByText("京东运维会话管理")).toBeInTheDocument();
    expect(screen.getByText(/返回业务页面：\/tasks\/new/)).toBeInTheDocument();
  });

  it("updates the confirm page when a task snapshot restores JD candidates", async () => {
    let snapshotHandler: ((event: MessageEvent<string>) => void) | undefined;
    vi.mocked(createTaskEventsSource).mockReturnValue({
      addEventListener: vi.fn((_type: string, handler: EventListenerOrEventListenerObject) => {
        snapshotHandler = handler as (event: MessageEvent<string>) => void;
      }),
      close: vi.fn(),
      removeEventListener: vi.fn()
    } as unknown as EventSource);

    vi.mocked(getTask).mockResolvedValue({
      task: {
        taskId: "task-confirm-live",
        query: "iPhone 15",
        createdAt: "2026-04-07T09:00:00.000Z",
        updatedAt: "2026-04-07T09:00:00.000Z",
        perLinkLimit: 100,
        taskTotalLimit: 500,
        taskStatus: "AwaitingConfirmation",
        taskStage: "confirmation",
        platformRuns: [
          {
            platform: "tmall",
            searchRequirement: "recommended",
            status: "AwaitingSelection",
            candidateCount: 1,
            selectedCandidateIds: [],
            lastUpdatedAt: "2026-04-07T09:00:00.000Z"
          },
          {
            platform: "jd",
            searchRequirement: "required",
            status: "SearchBlocked",
            candidateCount: 0,
            selectedCandidateIds: [],
            reason: "waiting for ops recovery",
            lastUpdatedAt: "2026-04-07T09:00:00.000Z"
          }
        ],
        platformCandidates: {
          tmall: [],
          jd: []
        },
        events: [],
        reportVersions: []
      }
    } as any);
    vi.mocked(getTaskCandidates)
      .mockResolvedValueOnce({
        candidates: {
          tmall: [],
          jd: []
        }
      } as any)
      .mockResolvedValue({
        candidates: {
          tmall: [],
          jd: [
            {
              candidateId: "jd-100068388533",
              platform: "jd",
              title: "Apple iPhone 15",
              price: 3898,
              priceLabel: "CNY 3898",
              storeName: "JD Self Operated",
              productUrl: "https://item.jd.com/100068388533.html",
              imageUrl: "https://img14.360buyimg.com/example.jpg",
              salesHint: "sold 500+",
              specLabel: "128GB",
              highlights: ["A16"]
            }
          ]
        }
      } as any);

    renderWithProviders(<App />, ["/tasks/task-confirm-live/confirm"]);

    expect(await screen.findByText("waiting for ops recovery")).toBeInTheDocument();

    await act(async () => {
      snapshotHandler?.(
        new MessageEvent("task.snapshot", {
          data: JSON.stringify({
            task: {
              taskId: "task-confirm-live",
              query: "iPhone 15",
              createdAt: "2026-04-07T09:00:00.000Z",
              updatedAt: "2026-04-07T09:01:00.000Z",
              perLinkLimit: 100,
              taskTotalLimit: 500,
              taskStatus: "AwaitingConfirmation",
              taskStage: "confirmation",
              platformRuns: [
                {
                  platform: "tmall",
                  searchRequirement: "recommended",
                  status: "AwaitingSelection",
                  candidateCount: 1,
                  selectedCandidateIds: [],
                  lastUpdatedAt: "2026-04-07T09:00:00.000Z"
                },
                {
                  platform: "jd",
                  searchRequirement: "required",
                  status: "AwaitingSelection",
                  candidateCount: 1,
                  selectedCandidateIds: [],
                  lastUpdatedAt: "2026-04-07T09:01:00.000Z"
                }
              ],
              platformCandidates: {
                tmall: [],
                jd: []
              },
              events: [],
              reportVersions: []
            }
          })
        })
      );
    });

    expect(await screen.findByText("Apple iPhone 15")).toBeInTheDocument();
    await waitFor(() => {
      expect(getTaskCandidates).toHaveBeenCalledTimes(2);
    });
  });

  it("imports jd managed session payload from the ops page", async () => {
    const user = userEvent.setup();

    renderWithProviders(<App />, ["/ops/session-manager?platform=jd&from=/tasks/new"]);

    await user.clear(await screen.findByLabelText("Cookie Header"));
    await user.type(screen.getByLabelText("Cookie Header"), "thor=masked; pin=masked;");
    await user.type(
      screen.getByLabelText("Detail Template URL"),
      "https://api.m.jd.com/?functionId=pc_detailpage_wareBusiness"
    );
    await user.type(
      screen.getByLabelText("Reviews Template URL"),
      "https://api.m.jd.com/?functionId=getLegoWareDetailComment"
    );
    await user.click(screen.getByRole("button", { name: "注入京东会话" }));

    await waitFor(() => {
      expect(importJdManagedSession).toHaveBeenCalledWith(
        expect.objectContaining({
          cookieHeader: "thor=masked; pin=masked;",
          detailTemplateUrl: "https://api.m.jd.com/?functionId=pc_detailpage_wareBusiness",
          reviewsTemplateUrl: "https://api.m.jd.com/?functionId=getLegoWareDetailComment"
        })
      );
    });
  });

  it("imports tmall managed session payload from the unified ops page", async () => {
    const user = userEvent.setup();

    renderWithProviders(<App />, ["/ops/session-manager?platform=tmall&from=/tasks/new"]);

    await user.clear(await screen.findByLabelText("Cookie Header"));
    await user.type(
      screen.getByLabelText("Cookie Header"),
      "_m_h5_tk=masked_token_123; cookie2=masked;"
    );
    await user.type(
      screen.getByLabelText("Detail Template URL"),
      "https://detail.tmall.com/item.htm?id=934454505228"
    );
    await user.type(
      screen.getByLabelText("Reviews Template URL"),
      "https://h5api.m.tmall.com/h5/mtop.taobao.rate.detaillist.get/6.0/?data=%7B%22auctionNumId%22%3A%22934454505228%22%7D"
    );
    await user.click(screen.getByRole("button", { name: "注入天猫会话" }));

    await waitFor(() => {
      expect(importTmallManagedSession).toHaveBeenCalledWith(
        expect.objectContaining({
          cookieHeader: "_m_h5_tk=masked_token_123; cookie2=masked;",
          detailTemplateUrl: "https://detail.tmall.com/item.htm?id=934454505228",
          reviewsTemplateUrl:
            "https://h5api.m.tmall.com/h5/mtop.taobao.rate.detaillist.get/6.0/?data=%7B%22auctionNumId%22%3A%22934454505228%22%7D"
        })
      );
    });
  });
});
