import {
  ApiDeploymentListParams,
  MachinePresetName,
  RunStatus,
} from "@trigger.dev/core/v3/schemas";
import { z } from "zod";

export const ProjectRefSchema = z
  .string()
  .describe(
    "The trigger.dev project ref, starts with proj_. We will attempt to automatically detect the project ref if running inside a directory that includes a trigger.config.ts file, or if you pass the --project-ref option to the MCP server."
  )
  .optional();

export const CreateProjectInOrgInput = z.object({
  orgParam: z
    .string()
    .describe(
      "The organization to create the project in, can either be the organization slug or the ID. Use the list_orgs tool to get a list of organizations and ask the user to select one."
    ),
  name: z.string().describe("The name of the project to create."),
});

export type CreateProjectInOrgInput = z.output<typeof CreateProjectInOrgInput>;

export const InitializeProjectInput = z.object({
  orgParam: z
    .string()
    .describe(
      "The organization to create the project in, can either be the organization slug or the ID. Use the list_orgs tool to get a list of organizations and ask the user to select one."
    ),
  projectRef: ProjectRefSchema,
  projectName: z
    .string()
    .describe(
      "The name of the project to create. If projectRef is not provided, we will use this name to create a new project in the organization you select."
    ),
  cwd: z.string().describe("The current working directory of the project").optional(),
});

export type InitializeProjectInput = z.output<typeof InitializeProjectInput>;

export const CommonProjectsInput = z.object({
  projectRef: ProjectRefSchema,
  configPath: z
    .string()
    .describe(
      "The path to the trigger.config.ts file. Only used when the trigger.config.ts file is not at the root dir (like in a monorepo setup). If not provided, we will try to find the config file in the current working directory"
    )
    .optional(),
  environment: z
    .enum(["dev", "staging", "prod", "preview"])
    .describe("The environment to get tasks for")
    .default("dev"),
  branch: z
    .string()
    .describe("The branch to get tasks for, only used for preview environments")
    .optional(),
});

export type CommonProjectsInput = z.output<typeof CommonProjectsInput>;

export const TriggerTaskInput = CommonProjectsInput.extend({
  taskId: z
    .string()
    .describe(
      "The ID/slug of the task to trigger. Use the get_tasks tool to get a list of tasks and ask the user to select one if it's not clear which one to use."
    ),
  payload: z
    .any()
    .describe(
      "The payload to trigger the task with. Should match the task's payload schema. Not a JSON string, but the actual payload object"
    ),
  options: z
    .object({
      queue: z
        .object({
          name: z
            .string()
            .describe(
              "The name of the queue to trigger the task in, by default will use the queue configured in the task"
            ),
        })
        .optional(),
      delay: z
        .string()
        .or(z.coerce.date())
        .describe("The delay before the task run is executed")
        .optional(),
      idempotencyKey: z.string().describe("The idempotency key to use for the task run").optional(),
      machine: MachinePresetName.describe("The machine preset to use for the task run").optional(),
      maxAttempts: z
        .number()
        .int()
        .describe("The maximum number of attempts to retry the task run")
        .optional(),
      maxDuration: z
        .number()
        .describe("The maximum duration in seconds of the task run")
        .optional(),
      tags: z
        .array(z.string())
        .describe(
          "Tags to add to the task run. Must be less than 128 characters and cannot have more than 5"
        )
        .optional(),
      ttl: z
        .string()
        .or(z.number().nonnegative().int())
        .describe(
          "The time to live of the task run. If the run doesn't start executing within this time, it will be automatically cancelled."
        )
        .default("10m"),
    })
    .optional(),
});

export type TriggerTaskInput = z.output<typeof TriggerTaskInput>;

export const CommonRunsInput = CommonProjectsInput.extend({
  runId: z.string().describe("The ID of the run to get the details of, starts with run_"),
});

export type CommonRunsInput = z.output<typeof CommonRunsInput>;

export const WaitForRunInput = CommonRunsInput.extend({
  timeoutInSeconds: z
    .number()
    .describe(
      "The maximum time in seconds to wait for the run to complete. If the run doesn't complete within this time, the current state of the run will be returned. Defaults to 60 seconds."
    )
    .default(60),
});

export type WaitForRunInput = z.output<typeof WaitForRunInput>;

export const GetRunDetailsInput = CommonRunsInput.extend({
  maxTraceLines: z
    .number()
    .int()
    .describe("The maximum number of lines to show in the trace. Defaults to 500")
    .optional(),
});

export type GetRunDetailsInput = z.output<typeof GetRunDetailsInput>;

export const ListRunsInput = CommonProjectsInput.extend({
  cursor: z.string().describe("The cursor to use for pagination, starts with run_").optional(),
  limit: z
    .number()
    .int()
    .describe("The number of runs to list in a single page. Up to 100")
    .optional(),
  status: RunStatus.describe("Filter for runs with this run status").optional(),
  taskIdentifier: z.string().describe("Filter for runs that match this task identifier").optional(),
  version: z
    .string()
    .describe("Filter for runs that match this version, e.g. 20250808.3")
    .optional(),
  tag: z.string().describe("Filter for runs that include this tag").optional(),
  from: z.string().describe("Filter for runs created after this ISO 8601 timestamp").optional(),
  to: z.string().describe("Filter for runs created before this ISO 8601 timestamp").optional(),
  period: z
    .string()
    .describe("Filter for runs created in the last N time period. e.g. 7d, 30d, 365d")
    .optional(),
  machine: MachinePresetName.describe("Filter for runs that match this machine preset").optional(),
});

export type ListRunsInput = z.output<typeof ListRunsInput>;

export const CommonDeployInput = CommonProjectsInput.omit({
  environment: true,
}).extend({
  environment: z
    .enum(["staging", "prod", "preview"])
    .describe("The environment to trigger the task in")
    .default("prod"),
});

export type CommonDeployInput = z.output<typeof CommonDeployInput>;

export const DeployInput = CommonDeployInput.extend({
  skipPromotion: z
    .boolean()
    .describe("Skip promoting the deployment to the current deployment for the environment")
    .optional(),
  skipSyncEnvVars: z
    .boolean()
    .describe("Skip syncing environment variables when using the syncEnvVars extension")
    .optional(),
  skipUpdateCheck: z
    .boolean()
    .describe("Skip checking for @trigger.dev package updates")
    .optional(),
});

export type DeployInput = z.output<typeof DeployInput>;

export const ListDeploysInput = CommonDeployInput.extend(ApiDeploymentListParams);

export type ListDeploysInput = z.output<typeof ListDeploysInput>;

export const ListPreviewBranchesInput = z.object({
  projectRef: ProjectRefSchema,
  configPath: z
    .string()
    .describe(
      "The path to the trigger.config.ts file. Only used when the trigger.config.ts file is not at the root dir (like in a monorepo setup). If not provided, we will try to find the config file in the current working directory"
    )
    .optional(),
});

export type ListPreviewBranchesInput = z.output<typeof ListPreviewBranchesInput>;
