import type { Job, ScoutPost, ScoutRun, ScoutRunBrief } from "../../domain/types";
import { newId } from "../../lib/id";
import type { ListPage, ScoutResultListQuery, ScoutRunListQuery } from "../repos";

export type MockScoutRunRecord = {
  run: ScoutRun;
  posts: ScoutPost[];
};

export type ScoutRunRepository = {
  runScanFromBrief(brief: ScoutRunBrief): Promise<{ job: Job; run: ScoutRun }>;
  listRuns(query?: ScoutRunListQuery): Promise<ListPage<ScoutRun>>;
  listRunPosts(
    runId: string,
    query?: ScoutResultListQuery,
  ): Promise<ListPage<ScoutPost> & { run: ScoutRun }>;
  removeRun(runId: string): Promise<void>;
};

const DEFAULT_PAGE_SIZE = 20;
const MAX_PAGE_SIZE = 100;

function pageWindow(query?: { page?: number; pageSize?: number }): { page: number; pageSize: number } {
  const page = Math.max(1, Math.floor(query?.page ?? 1));
  const pageSize = Math.min(MAX_PAGE_SIZE, Math.max(1, Math.floor(query?.pageSize ?? DEFAULT_PAGE_SIZE)));
  return { page, pageSize };
}

function pageOf<T>(items: T[], query?: { page?: number; pageSize?: number }): ListPage<T> {
  const { page, pageSize } = pageWindow(query);
  const total = items.length;
  const totalPages = total === 0 ? 0 : Math.ceil(total / pageSize);
  const start = (page - 1) * pageSize;
  return {
    list: items.slice(start, start + pageSize),
    pagination: { page, pageSize, total, totalPages },
  };
}

function compareRuns(a: ScoutRun, b: ScoutRun): number {
  return b.created_at - a.created_at || b.id.localeCompare(a.id);
}

function comparePosts(a: ScoutPost, b: ScoutPost): number {
	if (a.score !== b.score) return b.score - a.score;
	const aPosted = a.posted_at != null && a.posted_at > 0;
  const bPosted = b.posted_at != null && b.posted_at > 0;
  if (aPosted !== bPosted) return aPosted ? -1 : 1;
  if (aPosted && bPosted) return (b.posted_at ?? 0) - (a.posted_at ?? 0) || b.id.localeCompare(a.id);
  return (b.created_at ?? 0) - (a.created_at ?? 0) || b.id.localeCompare(a.id);
}

function copyRun(run: ScoutRun): ScoutRun {
  return { ...run, shortfall_reasons: [...run.shortfall_reasons] };
}

function copyPost(post: ScoutPost): ScoutPost {
  return { ...post };
}

export function createMockScoutRepo(initial: MockScoutRunRecord[] = []): ScoutRunRepository {
  const records = initial.map((record) => ({
    run: copyRun(record.run),
    posts: record.posts.map(copyPost),
  }));

  return {
    async runScanFromBrief(brief) {
      const now = Date.now() * 1_000_000;
      const runId = newId("scout_run");
      const jobId = newId("job");
      const targetCount = Math.max(1, Math.floor(brief.target_count ?? 1));
      const run: ScoutRun = {
        id: runId,
        job_id: jobId,
        theme_key: brief.theme_key ?? brief.intent,
        theme_label: brief.theme_label ?? brief.intent,
        intent: brief.intent,
        mode: brief.mode,
        brand_id: brief.brand_id ?? null,
        target_count: targetCount,
        status: "succeeded",
        searched_count: 0,
        duplicate_count: 0,
        irrelevant_count: 0,
        eligible_count: 0,
        pending_count: 0,
        shortfall_count: targetCount,
        shortfall_reasons: ["source_exhausted"],
        created_at: now,
        started_at: now,
        completed_at: now,
      };
      records.push({ run, posts: [] });
      const job: Job = {
        id: jobId,
        template_type: "scout_scan",
        status: "succeeded",
        progress_summary: "海巡完成，但來源沒有足夠合格結果",
        progress_percent: 100,
        created_at: now,
        updated_at: now,
        completed_at: now,
      };
      return { job: { ...job }, run: copyRun(run) };
    },

    async listRuns(query) {
      let runs = records.map((record) => record.run);
      if (query?.brandId != null) runs = runs.filter((run) => run.brand_id === query.brandId);
      if (query?.mode != null) runs = runs.filter((run) => run.mode === query.mode);
      runs.sort(compareRuns);
      const result = pageOf(runs.map(copyRun), query);
      return result;
    },

    async listRunPosts(runId, query) {
      const record = records.find((item) => item.run.id === runId);
      if (!record) throw new Error("海巡批次不存在");
      const result = pageOf(record.posts.slice().sort(comparePosts).map(copyPost), query);
      return { ...result, run: copyRun(record.run) };
    },

    async removeRun(runId) {
      const index = records.findIndex((item) => item.run.id === runId);
      if (index < 0) throw new Error("海巡批次不存在");
      records.splice(index, 1);
    },
  };
}
