import { describe, expect, it } from "vitest";
import type { ScoutRun } from "../../domain/types";
import { scoutPostFixture } from "../../test/scoutFixtures";
import { createMockScoutRepo } from "./scoutRepo";

function runFixture(id: string, createdAt: number): ScoutRun {
  return {
    id,
    job_id: "job-" + id,
    theme_key: "theme|同一主題",
    theme_label: "同一主題",
    intent: "同一主題",
    mode: "theme",
    brand_id: "brand-1",
    target_count: 3,
    status: "succeeded",
    searched_count: 5,
    duplicate_count: 1,
    irrelevant_count: 1,
    eligible_count: 3,
    pending_count: 0,
    shortfall_count: 0,
    shortfall_reasons: [],
    created_at: createdAt,
    completed_at: createdAt + 10,
  };
}

describe("mock Scout run repository", () => {
  it("keeps same-theme runs independent and paginates runs", async () => {
    const repo = createMockScoutRepo([
      { run: runFixture("run-old", 1_700_000_000_000_000_000), posts: [] },
      { run: runFixture("run-new", 1_700_000_100_000_000_000), posts: [] },
    ]);

    const first = await repo.listRuns({ page: 1, pageSize: 1 });
    const second = await repo.listRuns({ page: 2, pageSize: 1 });
    expect(first.list.map((run) => run.id)).toEqual(["run-new"]);
    expect(second.list.map((run) => run.id)).toEqual(["run-old"]);
    expect(first.pagination.total).toBe(2);
    expect(first.pagination.totalPages).toBe(2);
  });

  it("sorts known posted time first, then puts unknown time at the bottom", async () => {
    const run = runFixture("run-time", 1_700_000_000_000_000_000);
    const repo = createMockScoutRepo([
      {
        run,
        posts: [
          scoutPostFixture({ id: "unknown", run_id: run.id, posted_at: undefined, created_at: 50 }),
          scoutPostFixture({ id: "known-old", run_id: run.id, posted_at: 100, created_at: 10 }),
          scoutPostFixture({ id: "known-new", run_id: run.id, posted_at: 200, created_at: 1 }),
        ],
      },
    ]);

    const first = await repo.listRunPosts(run.id, { page: 1, pageSize: 2 });
    const second = await repo.listRunPosts(run.id, { page: 2, pageSize: 2 });
    expect(first.list.map((post) => post.id)).toEqual(["known-new", "known-old"]);
    expect(second.list.map((post) => post.id)).toEqual(["unknown"]);
    expect(first.pagination.total).toBe(3);
    expect(first.pagination.totalPages).toBe(2);
    expect(first.run.id).toBe(run.id);
  });

  it("uses score as the primary result order", async () => {
    const run = runFixture("run-score", 1_700_000_000_000_000_000);
    const repo = createMockScoutRepo([
      {
        run,
        posts: [
          scoutPostFixture({ id: "new-weak", run_id: run.id, score: 40, posted_at: 300 }),
          scoutPostFixture({ id: "old-strong", run_id: run.id, score: 90, posted_at: 100 }),
        ],
      },
    ]);

    const page = await repo.listRunPosts(run.id, { page: 1, pageSize: 2 });
    expect(page.list.map((post) => post.id)).toEqual(["old-strong", "new-weak"]);
  });

  it("creates unique runs and removes only the selected run", async () => {
    const repo = createMockScoutRepo();
    const brief = {
      intent: "新品上市痛點",
      mode: "theme" as const,
      pains: [],
      tags: [],
      periphery: [],
      scan_terms: ["新品上市"],
      theme_key: "theme|新品上市",
      theme_label: "新品上市",
    };
    const first = await repo.runScanFromBrief(brief);
    const second = await repo.runScanFromBrief(brief);
    expect(first.run.id).not.toBe(second.run.id);
    expect((await repo.listRuns()).pagination.total).toBe(2);
    await repo.removeRun(first.run.id);
    expect((await repo.listRuns()).list.map((run) => run.id)).toEqual([second.run.id]);
  });
});
