import { mock } from "bun:test";
import { Hono } from "hono";
import type { DebugDeps } from "@/server/routes/debug.js";

/**
 * Creates a minimal stub for DebugDeps.
 * Overrides let individual tests supply specific return values.
 */
export function createDebugDeps(overrides: Partial<DebugDeps> = {}): DebugDeps {
  const defaultJiraClient = {
    getIssue: mock(async () => ({
      id: "1",
      key: "SQDP-1",
      summary: "Test issue",
      description: null,
      issueType: "Bug",
      status: "To Do",
      created: null,
      acceptanceCriteria: null,
      stacktrace: null,
      flow: null,
      assignee: null,
      parent: null,
      subtasks: [],
      children: [],
      attachments: [],
      comments: [],
      components: [],
    })),
    searchIssues: mock(async () => ({ issues: [], total: 0 })),
    getMyself: mock(async () => ({
      accountId: "bot-id",
      displayName: "hu-agent",
      emailAddress: "bot@example.com",
    })),
    getUserByEmail: mock(async () => null),
    findUserByEmail: mock(async () => null),
    getTransitions: mock(async () => []),
    addComment: mock(async () => ({ id: "comment-1" })),
    transitionIssue: mock(async () => {}),
    createSubtask: mock(async () => ({ id: "2", key: "SQDP-2" })),
    listProjects: mock(async () => ({ values: [], total: 0 })),
    getIssueComponents: mock(async () => []),
    resolveAccountIdForBotEmail: mock(async () => null),
    getLastStatusChangeAuthor: mock(async () => null),
    getLastStatusChangeDates: mock(async () => new Map()),
  } as unknown as DebugDeps["jiraClient"];

  const defaultCursorCloudClient = {
    listModels: mock(async () => []),
    getAgentDetails: mock(async () => ({ id: "agent-1", name: "Test Agent", status: "FINISHED" })),
    getConversation: mock(async () => ({ id: "conv-1", messages: [] })),
  } as unknown as DebugDeps["cursorCloudClient"];

  const defaultPipeline = {
    execute: mock(async () => ({ success: true, issueKey: "SQDP-1", outcome: "completed" })),
    triage: mock(async () => ({
      verdict: "PROCEED",
      title: "Fix login",
      summary: "Looks good.",
      questions: null,
      raw: "raw output",
    })),
    evaluateCardReadiness: mock(async () => ({
      verdict: "PROCEED",
      title: null,
      summary: "Card is ready.",
      questions: null,
      raw: "raw output",
    })),
  } as unknown as DebugDeps["pipeline"];

  const defaultRepoRegistry = {
    getAll: mock(() => []),
    getByName: mock((_name: string) => undefined),
  } as unknown as DebugDeps["repoRegistry"];

  const defaultRepoSelector = {
    select: mock(() => null),
  } as unknown as DebugDeps["repoSelector"];

  const defaultQueue = {
    enqueue: mock(async () => {}),
    start: mock(() => {}),
    stop: mock(() => {}),
    isBusy: mock(() => false),
    getCurrentJobKind: mock(() => null),
    pendingCount: mock(() => 0),
    getCurrentJobKey: mock(() => null),
    getPendingJobKeys: mock(() => []),
  } as unknown as DebugDeps["queue"];

  const logger = {
    info: mock(() => {}),
    debug: mock(() => {}),
    warn: mock(() => {}),
    error: mock(() => {}),
    child: mock(function (this: unknown) {
      return this;
    } as () => unknown),
  } as unknown as DebugDeps["logger"];

  const defaultJiraPoller = {
    poll: mock(async () => 0),
  } as unknown as DebugDeps["jiraPoller"];
  const defaultTicketReviewPoller = {
    poll: mock(async () => 0),
  } as unknown as DebugDeps["ticketReviewPoller"];
  const defaultPrCommentPoller = {
    poll: mock(async () => 0),
  } as unknown as DebugDeps["prCommentPoller"];
  const defaultPrMentionPoller = {
    poll: mock(async () => 0),
  } as unknown as DebugDeps["prMentionPoller"];

  return {
    jiraClient: defaultJiraClient,
    cursorCloudClient: defaultCursorCloudClient,
    pipeline: defaultPipeline,
    repoRegistry: defaultRepoRegistry,
    repoSelector: defaultRepoSelector,
    getGitHubToken: mock(async () => "ghs_test_token"),
    jiraDomain: "test-company",
    workdirPath: "/tmp/test-workdir",
    githubBotUser: "hu-agent[bot]",
    queue: defaultQueue,
    logger,
    datadogLogsClient: null,
    slackNotifier: undefined,
    slackBotToken: undefined,
    slackDailyReportChannelId: undefined,
    squadScope: [],
    botEmail: "bot@example.com",
    jiraPoller: defaultJiraPoller,
    ticketReviewPoller: defaultTicketReviewPoller,
    prCommentPoller: defaultPrCommentPoller,
    prMentionPoller: defaultPrMentionPoller,
    slackMentionPoller: undefined,
    dailyReportScheduler: undefined,
    ...overrides,
  };
}

/**
 * Creates a Hono app that mounts the debug routes under /hu-agent prefix.
 * This mirrors how src/server/app.ts mounts them.
 */
export async function createTestDebugApp(depsOverrides: Partial<DebugDeps> = {}): Promise<Hono> {
  const { createDebugRoutes } = await import("@/server/routes/debug.js");
  const deps = createDebugDeps(depsOverrides);
  const app = new Hono();
  app.route("/hu-agent", createDebugRoutes(deps));
  return app;
}

/** Fires a GET request against the test app. Returns the Response. */
export async function fireGet(app: Hono, path: string): Promise<Response> {
  return app.request(path);
}

/** Fires a POST request against the test app with a JSON body. */
export async function firePost(app: Hono, path: string, body: unknown): Promise<Response> {
  return app.request(path, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
}
