import { createMcpServer, mcpTool } from '@inharness-ai/agent-adapters';
import { z } from 'zod';
import { DomainError } from '../../services/tags.js';
export function createEndpointToolsServer(deps) {
    const ok = (payload) => ({
        content: [{ type: 'text', text: JSON.stringify(payload) }],
    });
    const fail = (err) => {
        const code = err instanceof DomainError ? err.code : 'INTERNAL';
        const message = err instanceof Error ? err.message : String(err);
        return {
            content: [{ type: 'text', text: JSON.stringify({ error: message, code }) }],
            isError: true,
        };
    };
    const createEndpoint = mcpTool('create_endpoint', 'Create a new HTTP endpoint entity. Generates slug from method+path. Use to define structured API endpoints in the specification.', {
        method: z.string().describe('HTTP method: GET, POST, PUT, PATCH, DELETE'),
        path: z.string().describe('URL path, e.g. /api/users/:id'),
        summary: z.string().optional(),
        description: z.string().optional(),
        tags: z.array(z.string()).optional(),
    }, async (args) => {
        try {
            const ep = deps.endpointService.create({
                method: String(args.method).toUpperCase(),
                path: String(args.path),
                summary: args.summary,
                description: args.description,
                tags: args.tags,
            }, 'agent');
            deps.ws.broadcast({ kind: 'entity:changed', entityType: 'endpoint', slug: ep.slug });
            return ok({ id: ep.slug, slug: ep.slug, type: 'endpoint' });
        }
        catch (err) {
            return fail(err);
        }
    });
    const getEndpoint = mcpTool('get_endpoint', 'Get full details of an endpoint by slug. Returns all fields, tags, and related DTOs. Use to inspect endpoint details.', { slug: z.string() }, async (args) => {
        const ep = deps.endpointService.getBySlug(String(args.slug));
        if (!ep)
            return fail(new DomainError('NOT_FOUND', `endpoint '${args.slug}' not found`));
        return ok(ep);
    });
    const updateEndpoint = mcpTool('update_endpoint', 'Update endpoint fields (partial update). Only provided fields are changed. Use newSlug for explicit rename; otherwise slug auto-regenerates if method/path change.', {
        slug: z.string(),
        data: z
            .object({
            method: z.string().optional(),
            path: z.string().optional(),
            summary: z.string().optional(),
            description: z.string().nullable().optional(),
        })
            .describe('Partial fields to update'),
        newSlug: z.string().optional(),
    }, async (args) => {
        try {
            const data = args.data;
            const ep = deps.endpointService.update(String(args.slug), {
                method: data.method ? String(data.method).toUpperCase() : undefined,
                path: data.path,
                summary: data.summary,
                description: data.description,
                newSlug: args.newSlug,
            }, 'agent');
            const slugChanged = ep.slug !== args.slug;
            if (slugChanged) {
                await deps.referencesService.propagateSlugChange('endpoint', String(args.slug), ep.slug);
            }
            deps.ws.broadcast({ kind: 'entity:changed', entityType: 'endpoint', slug: ep.slug });
            return ok({ slug: ep.slug, updated: true });
        }
        catch (err) {
            return fail(err);
        }
    });
    const deleteEndpoint = mcpTool('delete_endpoint', 'Delete an endpoint. Returns list of pages with broken references. Use with caution.', { slug: z.string() }, async (args) => {
        try {
            const slug = String(args.slug);
            const refs = await deps.referencesService.findReferences('endpoint', slug);
            const result = deps.endpointService.remove(slug, 'agent');
            deps.ws.broadcast({ kind: 'entity:changed', entityType: 'endpoint', slug });
            return ok({
                deleted: true,
                brokenReferences: refs.map((r) => ({ pagePath: r.pagePath, count: 1 })),
            });
        }
        catch (err) {
            return fail(err);
        }
    });
    const listEndpoints = mcpTool('list_endpoints', 'List endpoints with optional filtering by tags or search text. Use to find endpoints or get an overview.', {
        tags: z.array(z.string()).optional(),
        tagFilter: z.enum(['and', 'or']).optional(),
        search: z.string().optional(),
        limit: z.number().optional(),
        offset: z.number().optional(),
    }, async (args) => {
        try {
            const list = deps.endpointService.list({
                tags: args.tags,
                tagFilter: args.tagFilter,
                search: args.search,
                limit: args.limit,
                offset: args.offset,
            });
            return ok({
                endpoints: list.map((e) => ({
                    slug: e.slug,
                    method: e.method,
                    path: e.path,
                    summary: e.summary,
                    tags: e.tags,
                })),
                total: list.length,
            });
        }
        catch (err) {
            return fail(err);
        }
    });
    const linkDto = mcpTool('link_dto', 'Link a DTO to an endpoint as request body, response, or error response. Optional HTTP status code for response/error. Idempotent.', {
        endpointSlug: z.string(),
        dtoSlug: z.string(),
        relation: z.enum(['request', 'response', 'error']),
        statusCode: z.number().optional(),
    }, async (args) => {
        try {
            deps.endpointService.linkDto(String(args.endpointSlug), String(args.dtoSlug), args.relation, args.statusCode ?? null);
            deps.ws.broadcast({ kind: 'entity:changed', entityType: 'endpoint', slug: String(args.endpointSlug) });
            return ok({ linked: true });
        }
        catch (err) {
            return fail(err);
        }
    });
    const unlinkDto = mcpTool('unlink_dto', 'Remove a DTO link from an endpoint. Omit statusCode to remove all links (endpoint, dto, relation).', {
        endpointSlug: z.string(),
        dtoSlug: z.string(),
        relation: z.enum(['request', 'response', 'error']),
        statusCode: z.number().optional(),
    }, async (args) => {
        try {
            deps.endpointService.unlinkDto(String(args.endpointSlug), String(args.dtoSlug), args.relation, args.statusCode ?? null);
            deps.ws.broadcast({ kind: 'entity:changed', entityType: 'endpoint', slug: String(args.endpointSlug) });
            return ok({ unlinked: true });
        }
        catch (err) {
            return fail(err);
        }
    });
    return createMcpServer({
        name: 'endpoint-tools',
        tools: [createEndpoint, getEndpoint, updateEndpoint, deleteEndpoint, listEndpoints, linkDto, unlinkDto],
    });
}
//# sourceMappingURL=mcp-server.js.map