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 and branchable development 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 trace lines per page. Defaults to 200. Use the `cursor` parameter to fetch subsequent pages."
    )
    .default(200),
  cursor: z
    .string()
    .describe(
      "Pagination cursor returned from a previous get_run_details call. Pass this to fetch the next page of trace events."
    )
    .optional(),
});

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

export const GetSpanDetailsInput = CommonRunsInput.extend({
  spanId: z
    .string()
    .describe(
      "The span ID to get details for. You can find span IDs in the trace output from get_run_details — they appear as [spanId] before each span message."
    ),
});

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

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(),
  region: z
    .string()
    .describe(
      "Filter for runs that executed in this region (the worker instance group masterQueue identifier, e.g. 'us-east-1' or 'main')"
    )
    .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 QueryInput = CommonProjectsInput.extend({
  query: z
    .string()
    .describe(
      "The TRQL query to execute. TRQL is a SQL-style language for analyzing your Trigger.dev data. Use the get_query_schema tool first to discover available tables and columns."
    ),
  scope: z
    .enum(["environment", "project", "organization"])
    .default("environment")
    .describe(
      "Data access scope. 'environment' (default) limits to the current environment, 'project' spans all environments, 'organization' spans all projects."
    ),
  period: z
    .string()
    .optional()
    .describe("Time period shorthand, e.g. '1h', '7d', '30d'. Mutually exclusive with from/to."),
  from: z.string().optional().describe("Start of time range (ISO 8601). Must be paired with 'to'."),
  to: z.string().optional().describe("End of time range (ISO 8601). Must be paired with 'from'."),
});

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

export const QuerySchemaInput = CommonProjectsInput.pick({
  projectRef: true,
  configPath: true,
  environment: true,
  branch: true,
}).extend({
  table: z
    .string()
    .describe("The table name to get the schema for (e.g. 'runs', 'metrics', 'llm_metrics')."),
});

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

export const ListDashboardsInput = CommonProjectsInput.pick({
  projectRef: true,
  configPath: true,
  environment: true,
  branch: true,
});

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

export const RunDashboardQueryInput = CommonProjectsInput.extend({
  dashboardKey: z
    .string()
    .describe(
      "The dashboard key (e.g. 'overview', 'llm'). Use list_dashboards to discover available dashboards."
    ),
  widgetId: z
    .string()
    .describe(
      "The widget ID to execute. Use list_dashboards to see available widget IDs and their queries."
    ),
  period: z
    .string()
    .optional()
    .describe("Time period shorthand, e.g. '1h', '7d', '30d'. Defaults to 1d."),
  from: z.string().optional().describe("Start of time range (ISO 8601). Must be paired with 'to'."),
  to: z.string().optional().describe("End of time range (ISO 8601). Must be paired with 'from'."),
  scope: z
    .enum(["environment", "project", "organization"])
    .default("environment")
    .describe("Data access scope."),
});

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

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>;
