import type { Prisma } from "@capakraken/db"; import type { TRPCContext } from "../../trpc.js"; import { CreateCountrySchema, CreateMetroCitySchema, UpdateCountrySchema, UpdateMetroCitySchema, } from "@capakraken/shared"; import { z } from "zod"; import type { ToolContext, ToolDef, ToolExecutor } from "./shared.js"; type AssistantToolErrorResult = { error: string }; type CountryRecord = { id: string; code: string; name: string; dailyWorkingHours: number; scheduleRules?: Prisma.JsonValue | null; isActive?: boolean | null; metroCities?: Array<{ id: string; name: string }> | null; _count?: { resources?: number | null } | null; }; type MetroCityRecord = { id: string; name: string; }; type CountryMetroAdminDeps = { createCountryCaller: (ctx: TRPCContext) => { create: (params: z.input) => Promise; update: (params: { id: string; data: z.input; }) => Promise; createCity: (params: z.input) => Promise; updateCity: (params: { id: string; data: z.input; }) => Promise; deleteCity: (params: { id: string }) => Promise<{ name?: string | null }>; }; createScopedCallerContext: (ctx: ToolContext) => TRPCContext; assertAdminRole: (ctx: ToolContext) => void; formatCountry: (country: CountryRecord) => unknown; toAssistantCountryMutationError: ( error: unknown, ) => AssistantToolErrorResult | null; toAssistantMetroCityMutationError: ( error: unknown, ) => AssistantToolErrorResult | null; }; export const countryMetroAdminToolDefinitions: ToolDef[] = [ { type: "function", function: { name: "create_country", description: "Create a country with daily working hours and optional schedule rules. Admin role required. Always confirm first.", parameters: { type: "object", properties: { code: { type: "string", description: "ISO country code such as DE or ES." }, name: { type: "string", description: "Country name." }, dailyWorkingHours: { type: "number", description: "Standard daily working hours." }, scheduleRules: { type: "object", description: "Optional schedule rule object such as the Spain reduced-hours configuration.", }, }, required: ["code", "name"], }, }, }, { type: "function", function: { name: "update_country", description: "Update a country including working hours, schedule rules, or active state. Admin role required. Always confirm first.", parameters: { type: "object", properties: { id: { type: "string", description: "Country ID." }, data: { type: "object", properties: { code: { type: "string" }, name: { type: "string" }, dailyWorkingHours: { type: "number" }, scheduleRules: { type: ["object", "null"] }, isActive: { type: "boolean" }, }, }, }, required: ["id", "data"], }, }, }, { type: "function", function: { name: "create_metro_city", description: "Create a metro city for a country. Admin role required. Always confirm first.", parameters: { type: "object", properties: { countryId: { type: "string", description: "Country ID." }, name: { type: "string", description: "Metro city name." }, }, required: ["countryId", "name"], }, }, }, { type: "function", function: { name: "update_metro_city", description: "Rename a metro city. Admin role required. Always confirm first.", parameters: { type: "object", properties: { id: { type: "string", description: "Metro city ID." }, data: { type: "object", properties: { name: { type: "string" }, }, }, }, required: ["id", "data"], }, }, }, { type: "function", function: { name: "delete_metro_city", description: "Delete a metro city when no resource is assigned to it. Admin role required. Always confirm first.", parameters: { type: "object", properties: { id: { type: "string", description: "Metro city ID." }, }, required: ["id"], }, }, }, ]; export function createCountryMetroAdminExecutors( deps: CountryMetroAdminDeps, ): Record { return { async create_country(params: { code: string; name: string; dailyWorkingHours?: number; scheduleRules?: Prisma.JsonValue | null; }, ctx: ToolContext) { deps.assertAdminRole(ctx); const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx)); let created; try { created = await caller.create(CreateCountrySchema.parse(params)); } catch (error) { const mapped = deps.toAssistantCountryMutationError(error); if (mapped) { return mapped; } throw error; } return { __action: "invalidate" as const, scope: ["country", "resource", "holidayCalendar", "vacation"], success: true, country: deps.formatCountry(created), message: `Created country: ${created.name}`, }; }, async update_country(params: { id: string; data: { code?: string; name?: string; dailyWorkingHours?: number; scheduleRules?: Prisma.JsonValue | null; isActive?: boolean; }; }, ctx: ToolContext) { deps.assertAdminRole(ctx); const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx)); const input = { id: params.id, data: UpdateCountrySchema.parse(params.data), }; let updated; try { updated = await caller.update(input); } catch (error) { const mapped = deps.toAssistantCountryMutationError(error); if (mapped) { return mapped; } throw error; } return { __action: "invalidate" as const, scope: ["country", "resource", "holidayCalendar", "vacation"], success: true, country: deps.formatCountry(updated), message: `Updated country: ${updated.name}`, }; }, async create_metro_city(params: { countryId: string; name: string }, ctx: ToolContext) { deps.assertAdminRole(ctx); const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx)); let created; try { created = await caller.createCity(CreateMetroCitySchema.parse(params)); } catch (error) { const mapped = deps.toAssistantMetroCityMutationError(error); if (mapped) { return mapped; } throw error; } return { __action: "invalidate" as const, scope: ["country", "resource", "holidayCalendar", "vacation"], success: true, metroCity: created, message: `Created metro city: ${created.name}`, }; }, async update_metro_city(params: { id: string; data: { name?: string } }, ctx: ToolContext) { deps.assertAdminRole(ctx); const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx)); const input = { id: params.id, data: UpdateMetroCitySchema.parse(params.data), }; let updated; try { updated = await caller.updateCity(input); } catch (error) { const mapped = deps.toAssistantMetroCityMutationError(error); if (mapped) { return mapped; } throw error; } return { __action: "invalidate" as const, scope: ["country", "resource", "holidayCalendar", "vacation"], success: true, metroCity: updated, message: `Updated metro city: ${updated.name}`, }; }, async delete_metro_city(params: { id: string }, ctx: ToolContext) { deps.assertAdminRole(ctx); const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx)); let deleted; try { deleted = await caller.deleteCity({ id: params.id }); } catch (error) { const mapped = deps.toAssistantMetroCityMutationError(error); if (mapped) { return mapped; } throw error; } return { __action: "invalidate" as const, scope: ["country", "resource", "holidayCalendar", "vacation"], success: true, message: `Deleted metro city: ${deleted.name ?? params.id}`, }; }, }; }