"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateTypesFromSteps = exports.generateTypesString = void 0;
const guards_1 = require("../guards");
const generate_type_from_schema_1 = require("./generate-type-from-schema");
const generate_types_from_response_1 = require("./generate-types-from-response");
const merge_schemas_1 = require("./merge-schemas");
const schema_types_1 = require("./schema.types");
const generateTypesString = (handlers) => {
    return `/**
 * Automatically generated types for motia
 * Do NOT edit this file manually.
 * 
 * Consider adding this file to .prettierignore and eslint ignore.
 */
import { EventHandler, ApiRouteHandler, ApiResponse } from 'motia'

declare module 'motia' {
  type Handlers = {
    ${Object.entries(handlers)
        .map(([key, { type, generics }]) => `'${key}': ${type}<${generics.join(', ')}>`)
        .join('\n    ')
        .trim()}
  }
}`;
};
exports.generateTypesString = generateTypesString;
const generateTypesFromSteps = (steps, printer) => {
    const handlers = {};
    const topics = {};
    const topicsSchemas = {};
    const topicsSteps = {};
    for (const step of steps) {
        if ((0, guards_1.isEventStep)(step) && step.config.input) {
            for (const topic of step.config.subscribes) {
                const existingSchema = topicsSchemas[topic];
                topicsSteps[topic] = topicsSteps[topic] ?? [];
                topicsSteps[topic].push(step);
                try {
                    const input = step.config.input;
                    const schema = existingSchema ? (0, merge_schemas_1.mergeSchemas)(existingSchema, input) : input;
                    topics[topic] = (0, generate_type_from_schema_1.generateTypeFromSchema)(schema);
                    topicsSchemas[topic] = schema;
                }
                catch (error) {
                    if (error instanceof schema_types_1.JsonSchemaError) {
                        printer.printInvalidSchema(topic, topicsSteps[topic]);
                        // invalid schema, the topic should be ignored
                        topics[topic] = 'never';
                    }
                    else {
                        throw error;
                    }
                }
            }
        }
    }
    const generateEmitData = (emit) => {
        const emits = emit
            .reduce((acc, emit) => {
            const topic = typeof emit === 'string' ? emit : emit.topic;
            const topicType = topics[topic];
            if (topicType) {
                acc.push(`{ topic: '${topic.replace(/'/g, "\\'")}'; data: ${topicType} }`);
            }
            return acc;
        }, [])
            .join(' | ');
        return emits.length === 0 ? 'never' : emits;
    };
    for (const step of steps) {
        const emits = 'emits' in step.config ? generateEmitData(step.config.emits) : 'never';
        if ((0, guards_1.isEventStep)(step)) {
            const input = step.config.input ? (0, generate_type_from_schema_1.generateTypeFromSchema)(step.config.input) : 'never';
            handlers[step.config.name] = { type: 'EventHandler', generics: [input, emits] };
        }
        else if ((0, guards_1.isApiStep)(step)) {
            const input = step.config.bodySchema
                ? (0, generate_type_from_schema_1.generateTypeFromSchema)(step.config.bodySchema)
                : 'Record<string, unknown>';
            const result = step.config.responseSchema
                ? (0, generate_types_from_response_1.generateTypesFromResponse)(step.config.responseSchema)
                : 'unknown';
            handlers[step.config.name] = { type: 'ApiRouteHandler', generics: [input, result, emits] };
        }
        else if ((0, guards_1.isCronStep)(step)) {
            handlers[step.config.name] = { type: 'CronHandler', generics: [emits] };
        }
    }
    return handlers;
};
exports.generateTypesFromSteps = generateTypesFromSteps;
