/**
 * ⚠️ NO IMPORTS except modes.ts - this file is imported by Next.js and must avoid pulling in backend code.
 * All shared constants, types, and data used by both the Next.js app and the action runtime live here.
 * Other files in action/ re-export from this file for backward compatibility.
 */

import { type } from "arktype";
import type { Mode } from "./modes.ts";

// mcp name constant
export const ghPullfrogMcpName = "gh_pullfrog";

export interface AgentManifest {
  displayName: string;
  apiKeyNames: string[];
  url: string;
}

// agent manifest - static metadata about available agents
export const agentsManifest = {
  claude: {
    displayName: "Claude Code",
    apiKeyNames: ["anthropic_api_key"],
    url: "https://claude.com/claude-code",
  },
  codex: {
    displayName: "Codex CLI",
    apiKeyNames: ["openai_api_key"],
    url: "https://platform.openai.com/docs/guides/codex",
  },
  cursor: {
    displayName: "Cursor CLI",
    apiKeyNames: ["cursor_api_key"],
    url: "https://cursor.com/",
  },
  gemini: {
    displayName: "Gemini CLI",
    apiKeyNames: ["google_api_key", "gemini_api_key"],
    url: "https://ai.google.dev/gemini-api/docs",
  },
  opencode: {
    displayName: "OpenCode",
    apiKeyNames: [], // empty array means OpenCode accepts any API_KEY from environment
    url: "https://opencode.ai",
  },
} as const satisfies Record<string, AgentManifest>;

// agent name type - union of agent slugs
export type AgentName = keyof typeof agentsManifest;
export const AgentName = type.enumerated(...Object.keys(agentsManifest));

export type AgentApiKeyName = (typeof agentsManifest)[AgentName]["apiKeyNames"][number];

// base interface for common payload event fields
interface BasePayloadEvent {
  issue_number?: number;
  is_pr?: boolean;
  branch?: string;
  pr_title?: string;
  pr_body?: string | null;
  issue_title?: string;
  issue_body?: string | null;
  comment_id?: number;
  comment_body?: string;
  review_id?: number;
  review_body?: string | null;
  review_state?: string;
  review_comments?: any[];
  context?: any;
  thread?: any;
  pull_request?: any;
  check_suite?: {
    id: number;
    head_sha: string;
    head_branch: string | null;
    status: string | null;
    conclusion: string | null;
    url: string;
  };
  comment_ids?: number[] | "all";
  [key: string]: any;
}

interface PullRequestOpenedEvent extends BasePayloadEvent {
  trigger: "pull_request_opened";
  issue_number: number;
  is_pr: true;
  pr_title: string;
  pr_body: string | null;
  branch: string;
}

interface PullRequestReadyForReviewEvent extends BasePayloadEvent {
  trigger: "pull_request_ready_for_review";
  issue_number: number;
  is_pr: true;
  pr_title: string;
  pr_body: string | null;
  branch: string;
}

interface PullRequestReviewRequestedEvent extends BasePayloadEvent {
  trigger: "pull_request_review_requested";
  issue_number: number;
  is_pr: true;
  pr_title: string;
  pr_body: string | null;
  branch: string;
}

interface PullRequestReviewSubmittedEvent extends BasePayloadEvent {
  trigger: "pull_request_review_submitted";
  issue_number: number;
  is_pr: true;
  review_id: number;
  review_body: string | null;
  review_state: string;
  review_comments: any[];
  context: any;
  branch: string;
}

interface PullRequestReviewCommentCreatedEvent extends BasePayloadEvent {
  trigger: "pull_request_review_comment_created";
  issue_number: number;
  is_pr: true;
  pr_title: string;
  comment_id: number;
  comment_body: string;
  thread?: any;
  branch: string;
}

interface IssuesOpenedEvent extends BasePayloadEvent {
  trigger: "issues_opened";
  issue_number: number;
  issue_title: string;
  issue_body: string | null;
}

interface IssuesAssignedEvent extends BasePayloadEvent {
  trigger: "issues_assigned";
  issue_number: number;
  issue_title: string;
  issue_body: string | null;
}

interface IssuesLabeledEvent extends BasePayloadEvent {
  trigger: "issues_labeled";
  issue_number: number;
  issue_title: string;
  issue_body: string | null;
}

interface IssueCommentCreatedEvent extends BasePayloadEvent {
  trigger: "issue_comment_created";
  comment_id: number;
  comment_body: string;
  issue_number: number;
  // PR-specific fields (only present when is_pr is true)
  is_pr?: true;
  branch?: string;
  pr_title?: string;
  pr_body?: string | null;
}

interface CheckSuiteCompletedEvent extends BasePayloadEvent {
  trigger: "check_suite_completed";
  issue_number: number;
  is_pr: true;
  pr_title: string;
  pr_body: string | null;
  pull_request: any;
  branch: string;
  check_suite: {
    id: number;
    head_sha: string;
    head_branch: string | null;
    status: string | null;
    conclusion: string | null;
    url: string;
  };
}

interface WorkflowDispatchEvent extends BasePayloadEvent {
  trigger: "workflow_dispatch";
}

/** simplified review comment data for payload */
export interface ReviewCommentData {
  id: number;
  body: string;
  path: string;
  line: number | null;
  user: string | null;
  html_url: string;
  in_reply_to_id: number | null;
}

interface FixReviewEvent extends BasePayloadEvent {
  trigger: "fix_review";
  issue_number: number;
  is_pr: true;
  review_id: number;
  /** username of the person who triggered this action */
  triggerer: string;
  /** "all" to fix all comments, or specific comment IDs to fix */
  comment_ids: number[] | "all";
  /** comments the triggerer approved (via thumbs up) - these should be addressed */
  approved_comments: ReviewCommentData[];
  /** other comments in the review - for context only, do not address unless asked */
  unapproved_comments: ReviewCommentData[];
}

interface ImplementPlanEvent extends BasePayloadEvent {
  trigger: "implement_plan";
  issue_number: number;
  plan_comment_id: number;
  plan_content: string;
}

interface UnknownEvent extends BasePayloadEvent {
  trigger: "unknown";
}

// discriminated union for payload event based on trigger
// note: all events use issue_number for consistency (PRs are issues in GitHub's API)
export type PayloadEvent =
  | PullRequestOpenedEvent
  | PullRequestReadyForReviewEvent
  | PullRequestReviewRequestedEvent
  | PullRequestReviewSubmittedEvent
  | PullRequestReviewCommentCreatedEvent
  | IssuesOpenedEvent
  | IssuesAssignedEvent
  | IssuesLabeledEvent
  | IssueCommentCreatedEvent
  | CheckSuiteCompletedEvent
  | WorkflowDispatchEvent
  | FixReviewEvent
  | ImplementPlanEvent
  | UnknownEvent;

export interface DispatchOptions {
  /**
   * Sandbox mode flag - when true, restricts agent to read-only operations
   * (no Write, Web, or Bash access)
   */
  readonly sandbox?: boolean;

  /**
   * When true, disables progress comment (no "leaping into action" comment, no report_progress tool)
   */
  readonly disableProgressComment?: true;
}

// payload type for agent execution
export interface Payload extends DispatchOptions {
  "~pullfrog": true;

  /**
   * Agent slug identifier (e.g., "claude", "codex", "gemini")
   */
  readonly agent: AgentName | null;

  /**
   * The prompt/instructions for the agent to execute
   */
  readonly prompt: string;

  /**
   * Event data from webhook payload.
   * Discriminated union based on trigger field.
   */
  readonly event: PayloadEvent;

  /**
   * Execution mode configuration
   */
  modes: readonly Mode[];

  /**
   * Optional IDs of the issue, PR, or comment that the agent is working on
   */
  readonly comment_id?: number | null;
  readonly issue_id?: number | null;
  readonly pr_id?: number | null;
}
