import type { Prisma } from "@capakraken/db";
import type { TRPCContext } from "../../trpc.js";
import { withToolAccess, type ToolContext, type ToolDef, type 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 CountryReadmodelsDeps = {
  createCountryCaller: (ctx: TRPCContext) => {
    list: (params?: { isActive: boolean }) => Promise<CountryRecord[]>;
    getByIdentifier: (params: { identifier: string }) => Promise<CountryRecord>;
  };
  createScopedCallerContext: (ctx: ToolContext) => TRPCContext;
  formatCountry: (country: CountryRecord) => unknown;
  toAssistantCountryNotFoundError: (
    error: unknown,
  ) => AssistantToolErrorResult | null;
};

export const countryReadmodelToolDefinitions: ToolDef[] = withToolAccess([
  {
    type: "function",
    function: {
      name: "list_countries",
      description: "List countries including working hours, schedule rules, active flag, and metro cities.",
      parameters: {
        type: "object",
        properties: {
          includeInactive: { type: "boolean", description: "Include inactive countries. Default: false." },
          search: { type: "string", description: "Optional country code or name search." },
        },
      },
    },
  },
  {
    type: "function",
    function: {
      name: "get_country",
      description: "Get one country with schedule rules, active flag, metro cities, and resource count. Accepts ID, code, or name.",
      parameters: {
        type: "object",
        properties: {
          identifier: { type: "string", description: "Country ID, code, or name." },
        },
        required: ["identifier"],
      },
    },
  },
], {
  get_country: {
    requiresResourceOverview: true,
  },
});

export function createCountryReadmodelExecutors(
  deps: CountryReadmodelsDeps,
): Record<string, ToolExecutor> {
  return {
    async list_countries(
      params: { includeInactive?: boolean; search?: string },
      ctx: ToolContext,
    ) {
      const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx));
      const countries = await caller.list(
        params.includeInactive
          ? undefined
          : { isActive: true },
      );
      const normalizedSearch = params.search?.trim().toLowerCase();
      const filteredCountries = normalizedSearch
        ? countries.filter((country) =>
            country.code.toLowerCase().includes(normalizedSearch)
            || country.name.toLowerCase().includes(normalizedSearch))
        : countries;

      return {
        count: filteredCountries.length,
        countries: filteredCountries.map(deps.formatCountry),
      };
    },

    async get_country(
      params: { identifier: string },
      ctx: ToolContext,
    ) {
      const caller = deps.createCountryCaller(deps.createScopedCallerContext(ctx));
      let country;
      try {
        country = await caller.getByIdentifier({ identifier: params.identifier });
      } catch (error) {
        const mapped = deps.toAssistantCountryNotFoundError(error);
        if (mapped) {
          return mapped;
        }
        throw error;
      }

      return deps.formatCountry(country);
    },
  };
}
