import { z } from "zod";
export const SESSION_STORAGE_FILENAME = "skyramp_session_storage.json";
export const AUTH_PLACEHOLDER_TOKEN = "SKYRAMP_PLACEHOLDER_TOKEN";
export var ProgrammingLanguage;
(function (ProgrammingLanguage) {
    ProgrammingLanguage["PYTHON"] = "python";
    ProgrammingLanguage["TYPESCRIPT"] = "typescript";
    ProgrammingLanguage["JAVASCRIPT"] = "javascript";
    ProgrammingLanguage["JAVA"] = "java";
})(ProgrammingLanguage || (ProgrammingLanguage = {}));
export var TestType;
(function (TestType) {
    TestType["SMOKE"] = "smoke";
    TestType["FUZZ"] = "fuzz";
    TestType["CONTRACT"] = "contract";
    TestType["LOAD"] = "load";
    TestType["INTEGRATION"] = "integration";
    TestType["E2E"] = "e2e";
    TestType["UI"] = "ui";
    TestType["MOCK"] = "mock";
})(TestType || (TestType = {}));
export var HttpMethod;
(function (HttpMethod) {
    HttpMethod["GET"] = "GET";
    HttpMethod["POST"] = "POST";
    HttpMethod["PUT"] = "PUT";
    HttpMethod["DELETE"] = "DELETE";
    HttpMethod["PATCH"] = "PATCH";
    HttpMethod["HEAD"] = "HEAD";
    HttpMethod["OPTIONS"] = "OPTIONS";
})(HttpMethod || (HttpMethod = {}));
export var RuntimeEnvironment;
(function (RuntimeEnvironment) {
    RuntimeEnvironment["LOCAL"] = "local";
    RuntimeEnvironment["DOCKER"] = "docker";
    RuntimeEnvironment["KUBERNETES"] = "kubernetes";
})(RuntimeEnvironment || (RuntimeEnvironment = {}));
export const languageSchema = z.object({
    language: z
        .nativeEnum(ProgrammingLanguage)
        .describe("Programming language for the generated test (default: python). Must be one of: python, typescript, javascript, java"),
    framework: z
        .string()
        .describe("Testing framework to use (e.g., pytest for python, playwright for javascript and typescript, junit for java, etc.)"),
});
export const baseSchema = z.object({
    ...languageSchema.shape,
    deployDashboard: z
        .boolean()
        .default(false)
        .describe("Whether to deploy the Skyramp dashboard for test monitoring"),
    runtime: z
        .nativeEnum(RuntimeEnvironment)
        .default(RuntimeEnvironment.LOCAL)
        .describe("Runtime environment (docker, kubernetes, local)"),
    dockerNetwork: z
        .string()
        .default("")
        .describe("Docker network name to use for containerized testing"),
    dockerWorkerPort: z
        .number()
        .int()
        .min(0)
        .max(65535)
        .default(0)
        .describe("Port number for the Docker worker service"),
    k8sNamespace: z
        .string()
        .default("")
        .describe("Kubernetes namespace for deployment"),
    k8sConfig: z
        .string()
        .default("")
        .describe("Path to Kubernetes configuration file"),
    k8sContext: z.string().default("").describe("Kubernetes context to use"),
    authHeader: z
        .string()
        .default("")
        .describe("Name of the HTTP header that carries the auth credential. " +
        "Common values: 'Authorization' (Bearer/Basic/Token auth), 'X-Api-Key', 'X-Auth-Token', 'Cookie'. " +
        "Other accepted values: 'X-Access-Token', 'X-OAuth-Token', 'X-Client-ID', 'X-Client-Secret', 'X-Client-Token', " +
        "'X-GitHub-Token', 'X-Firebase-AppCheck', 'Proxy-Authorization', 'Fastly-Key', 'Heroku-Bearer'. " +
        "Pass empty string to skip auth entirely for unauthenticated endpoints. " +
        "This is the header KEY name (e.g., 'X-Api-Key'), NOT the token value."),
    authScheme: z
        .string()
        .default("")
        .describe("Only for Authorization headers. The literal prefix before the token " +
        "(e.g., 'Bearer' produces 'Authorization: Bearer <token>'). " +
        "Common values: 'Bearer', 'Basic', 'Token'. " +
        "If the API sends raw tokens with no prefix (e.g., 'Authorization: eyJ...'), leave empty or omit. " +
        "Ignored when authHeader is not 'Authorization'."),
    insecure: z
        .boolean()
        .default(false)
        .describe("Whether to allow insecure SSL connections for HTTPS endpoints"),
    output: z
        .string()
        .optional()
        .refine((val) => {
        if (!val || val === "")
            return true; // Allow empty string or undefined
        const validExtensions = [".py", ".ts", ".js", ".java"];
        return validExtensions.some((ext) => val.endsWith(ext));
    }, {
        message: "Output file must have one of these extensions: .py, .ts, .js, .java",
    })
        .describe("Name of the output test file. For Playwright framework, the file must match " +
        "*.spec.ts so Playwright can discover it " +
        "(e.g. contract_math_add.spec.ts, fuzz_orders.spec.ts). " +
        "For other frameworks (pytest, junit), standard extensions are fine (.py, .java). " +
        "Optional — when omitted, Skyramp generates a default name."),
    outputDir: z
        .string()
        .describe("MUST be absolute path to the directory where test files will be generated. If not provided, the CURRENT WORKING DIRECTORY will be used WITHOUT ANY SUBDIRECTORIES"),
    force: z
        .boolean()
        .default(true)
        .describe("Whether to overwrite existing files in the output directory"),
    mockPort: z
        .number()
        .int()
        .min(0)
        .max(65535)
        .default(0)
        .describe("Port number for the mock server"),
    optionalFields: z
        .boolean()
        .default(false)
        .describe("Whether to include optional fields in the generated test/mock"),
    prompt: z.string().describe("The prompt user provided to generate the test"),
});
export const basePlaywrightSchema = z.object({
    playwrightInput: z
        .string()
        .describe("MUST be absolute path to the playwright input file like /path/to/playwright-ui-test.zip and MUST be a zip file captured using start_trace_collection tool"),
    playwrightStoragePath: z
        .string()
        .optional()
        .describe("Path to LOAD existing playwright session storage for trace collection with playwright enabled. THE PATH MUST BE AN ABSOLUTE PATH LIKE /Users/<path>/<filename>.json"),
    playwrightSaveStoragePath: z
        .string()
        .optional()
        .describe(`Path to SAVE Playwright session storage after trace collection. Omit this argument to use the default — \`${SESSION_STORAGE_FILENAME}\` resolved against the active outputDir, which produces an absolute path like '/abs/outputDir/${SESSION_STORAGE_FILENAME}'. SAVES authentication state (cookies, localStorage, sessionStorage) when the browser closes. To LOAD existing auth state, use playwrightStoragePath instead. Can be a bare filename (joined with outputDir), a relative path, or an absolute path.`),
    playwrightViewportSize: z
        .union([
        z.enum(["", "hd", "full-hd", "2k"]),
        z.string().regex(/^\d+,\d+$/, "Custom viewport must be 'WIDTH,HEIGHT' format (e.g., '1920,1080')"),
    ])
        .default("")
        .describe("Viewport size for playwright browser. THE VALUE MUST BE IN THE FORMAT ['', 'hd', 'full-hd', '2k', 'x,y' e.g. '1920,1080' for 1920x1080 resolution]. DEFAULT VALUE IS ''. If set to '', the browser will use its default viewport size."),
    browser: z
        .enum(["chromium", "firefox", "webkit"])
        .default("chromium")
        .describe("Browser to use for Playwright trace collection. Supported browsers: 'chromium' (default), 'firefox', 'webkit'. Choose based on your testing requirements and target browser compatibility."),
    device: z
        .string()
        .default("")
        .describe("Device to emulate for Playwright trace collection. Supported devices include: 'iPhone 13', 'iPhone 13 Pro', 'Pixel 5', 'Galaxy S9+', 'iPad Pro', etc. Leave empty for no device emulation (desktop). Use specific device names for mobile/tablet testing."),
});
export const baseTraceSchema = z.object({
    trace: z
        .string()
        .describe("Absolute path to the trace file in JSON format (e.g., /path/to/trace.json). Must use .json extension only. Do not use .jsonl files."),
    include: z
        .array(z.string())
        .default([])
        .describe("List of endpoints or patterns to include in test generation."),
    exclude: z
        .array(z.string())
        .default([])
        .describe("List of endpoints or patterns to exclude from test generation."),
    ...baseSchema.shape,
});
// Base schema that all test tools share
export const baseTestSchema = {
    endpointURL: z
        .string()
        .describe("The full endpoint URL to test including base URL and path " +
        "(e.g., https://demoshop.skyramp.dev/api/v1/products). " +
        "MUST include both the base URL and the endpoint path — never just the base URL alone."),
    method: z
        .union([z.nativeEnum(HttpMethod), z.literal("")])
        .default("")
        .describe('HTTP method to use. DEFAULT: Use empty string ("") to test ALL available methods from OpenAPI schema (recommended). Only specify a specific method (GET, POST, PUT, DELETE, etc.) if user explicitly requests testing a single method only.'),
    apiSchema: z
        .string()
        .default("")
        .describe("MUST be absolute path(/path/to/openapi.json) to the OpenAPI/Swagger schema file or a URL to the OpenAPI/Swagger schema file(e.g. https://demoshop.skyramp.dev/openapi.json). DO NOT TRY TO ASSUME THE OPENAPI SCHEMA IF NOT PROVIDED. NOTE TO AI ASSISTANTS: You do not need to read the contents of this file - simply pass the file path as the backend will read and process it."),
    pathParams: z
        .string()
        .default("")
        .describe("Comma-separated path parameter values in the form 'key=value,key2=value2' (e.g., 'id=1,name=John'). " +
        "DO NOT populate this field unless the user has explicitly provided path parameter values. " +
        "For contract tests, parent path parameters are automatically handled via the parent provisioning mechanism (parentRequestData) — do NOT invent or guess values for those here. " +
        "Only supply this field if the user explicitly states specific path parameter values to use."),
    queryParams: z
        .string()
        .default("")
        .describe("MUST be string of comma separated values like 'id=1,name=John' for URL query parameters"),
    formParams: z
        .string()
        .default("")
        .describe("MUST be string of comma separated values like 'id=1,name=John' for form data parameters"),
    requestData: z
        .string()
        .default("")
        .refine((val) => {
        if (!val || val === "")
            return true;
        if (val.startsWith("@"))
            return true;
        try {
            JSON.parse(val);
            return true;
        }
        catch { /* not JSON */ }
        const trimmed = val.trim();
        // Accept common YAML patterns: document separator, mappings (key: val), sequences (- item)
        if (trimmed.startsWith("---"))
            return true;
        if (/^\w[\w\s]*:/.test(trimmed))
            return true; // YAML mapping: "key: value"
        if (trimmed.startsWith("-"))
            return true; // YAML sequence: "- item"
        return false;
    }, {
        message: "requestData must be valid JSON, YAML, or an absolute file path prefixed with '@'. " +
            "Received what appears to be plain text. Provide the actual request body as a JSON object.",
    })
        .describe("Sample request body data, provided either as an inline JSON/YAML string or as an absolute file path prefixed with '@' (e.g., @/absolute/path/to/file). " +
        "MUST be valid JSON or YAML — do NOT pass natural language descriptions."),
    responseStatusCode: z
        .string()
        .default("")
        .refine((val) => !val || /^\d{3}$/.test(val), { message: "Must be a 3-digit HTTP status code (e.g., '200', '404') or empty string" })
        .describe("Expected HTTP response status code (e.g., '200', '201', '404'). DO NOT ASSUME STATUS CODE IF NOT PROVIDED"),
    ...baseSchema.shape,
};
export const codeRefactoringSchema = z.object({
    codeReuse: z
        .boolean()
        .default(false)
        .describe("Whether to reuse existing code"),
    modularizeCode: z
        .boolean()
        .default(false)
        .describe("Whether to modularize the code"),
});
