import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { catalogApi, DEFAULT_SHOP_ID } from "../services/api-client.js";
import { errorResponse, textResponse } from "../services/error-handler.js";

function formatPrice(price: number): string {
  return new Intl.NumberFormat("vi-VN", {
    style: "currency",
    currency: "VND",
    maximumFractionDigits: 0,
  }).format(price);
}

interface ProductDto {
  id: string;
  shopId: string;
  name: string;
  description?: string;
  price: number;
  type: string;
  imageUrl?: string;
  sku?: string;
  barcode?: string;
  categoryId?: string;
  categoryName?: string;
  isActive: boolean;
  createdAt: string;
  updatedAt?: string;
}

export function registerCatalogTools(server: McpServer): void {
  // 1. list_products
  server.tool(
    "list_products",
    "List menu items/products for a shop. Returns name, price, category, stock status.",
    {
      shopId: z
        .string()
        .uuid()
        .optional()
        .describe("Shop ID (defaults to configured shop)"),
      categoryId: z
        .string()
        .uuid()
        .optional()
        .describe("Filter by category ID"),
      isActive: z
        .boolean()
        .optional()
        .describe("Filter by active status (omit to show all)"),
      page: z.number().int().positive().optional().default(1),
      pageSize: z
        .number()
        .int()
        .positive()
        .max(200)
        .optional()
        .default(20),
    },
    async ({ shopId, categoryId, isActive, page, pageSize }) => {
      try {
        const resolvedShopId = shopId ?? DEFAULT_SHOP_ID;
        const params: Record<string, unknown> = {
          shopId: resolvedShopId,
          page,
          pageSize,
        };
        if (isActive !== undefined) params.isActive = isActive;
        if (categoryId) params.categoryId = categoryId;

        const { data: res } = await catalogApi.get("/products", { params });

        // Response: { items: ProductDto[], totalCount, pageNumber, pageSize }
        const items: ProductDto[] = res?.items ?? res?.data?.items ?? [];
        const totalCount = res?.totalCount ?? res?.data?.totalCount ?? items.length;

        if (items.length === 0) {
          return textResponse("No products found for this shop.");
        }

        const header = `${"Name".padEnd(30)} | ${"Price".padStart(14)} | ${"Category".padEnd(20)} | Active`;
        const separator = "-".repeat(header.length);
        const rows = items.map((p) => {
          const name = (p.name ?? "—").slice(0, 29).padEnd(30);
          const price = formatPrice(p.price ?? 0).padStart(14);
          const category = (p.categoryName ?? "—").slice(0, 19).padEnd(20);
          const active = p.isActive !== false ? "Yes" : "No";
          return `${name} | ${price} | ${category} | ${active}`;
        });

        const output = [
          `Products for shop ${resolvedShopId} (page ${page}, showing ${items.length} of ${totalCount}):`,
          "",
          header,
          separator,
          ...rows,
        ].join("\n");

        return textResponse(output);
      } catch (err) {
        return errorResponse(err);
      }
    },
  );

  // 2. create_product
  server.tool(
    "create_product",
    "Create a new product/menu item in the shop catalog.",
    {
      shopId: z
        .string()
        .uuid()
        .optional()
        .describe("Shop ID (defaults to configured shop)"),
      name: z.string().min(1).max(200).describe("Product name"),
      description: z.string().max(1000).optional().describe("Product description"),
      price: z.number().positive().describe("Product price in VND"),
      type: z
        .string()
        .optional()
        .default("PreparedFood")
        .describe("Product type (e.g. PreparedFood, Beverage, RetailItem)"),
      categoryId: z.string().uuid().optional().describe("Category ID"),
      sku: z.string().optional().describe("Stock-keeping unit code"),
      imageUrl: z.string().url().optional().describe("Image URL"),
    },
    async ({ shopId, name, description, price, type, categoryId, sku, imageUrl }) => {
      try {
        const body: Record<string, unknown> = {
          shopId: shopId ?? DEFAULT_SHOP_ID,
          name,
          price,
          type,
        };
        if (description) body.description = description;
        if (categoryId) body.categoryId = categoryId;
        if (sku) body.sku = sku;
        if (imageUrl) body.imageUrl = imageUrl;

        const { data: res } = await catalogApi.post("/products", body);

        // Backend returns CreatedAtAction with raw Guid or { data: Guid }
        const productId =
          typeof res === "string" ? res :
          typeof res?.data === "string" ? res.data :
          res?.data?.id ?? res?.id ?? "unknown";

        return textResponse(
          `Product created successfully.\n` +
            `  ID   : ${productId}\n` +
            `  Name : ${name}\n` +
            `  Price: ${formatPrice(price)}`,
        );
      } catch (err) {
        return errorResponse(err);
      }
    },
  );

  // 3. update_product
  server.tool(
    "update_product",
    "Update an existing product's name, price, description, or category. Fetches current values first to avoid overwriting unchanged fields.",
    {
      productId: z.string().uuid().describe("Product ID to update"),
      name: z.string().min(1).max(200).optional().describe("New product name"),
      description: z.string().max(1000).optional().describe("New description"),
      price: z.number().positive().optional().describe("New price in VND"),
      categoryId: z.string().uuid().optional().describe("New category ID"),
      imageUrl: z.string().url().optional().describe("New image URL"),
    },
    async ({ productId, name, description, price, categoryId, imageUrl }) => {
      try {
        if (
          name === undefined &&
          description === undefined &&
          price === undefined &&
          categoryId === undefined &&
          imageUrl === undefined
        ) {
          return textResponse("No fields provided to update. Please specify at least one field.");
        }

        // Fetch current product to merge with partial updates
        const { data: current } = await catalogApi.get(`/products/${productId}`);
        const existing = current?.data ?? current;

        const body: Record<string, unknown> = {
          productId,
          name: name ?? existing?.name ?? "",
          price: price ?? existing?.price ?? 0,
          description: description ?? existing?.description ?? "",
          type: existing?.type ?? "PreparedFood",
          shopId: existing?.shopId ?? DEFAULT_SHOP_ID,
        };
        if (categoryId !== undefined) body.categoryId = categoryId;
        else if (existing?.categoryId) body.categoryId = existing.categoryId;
        if (imageUrl !== undefined) body.imageUrl = imageUrl;
        else if (existing?.imageUrl) body.imageUrl = existing.imageUrl;

        await catalogApi.put(`/products/${productId}`, body);

        const changes: Record<string, unknown> = {};
        if (name !== undefined) changes.name = name;
        if (description !== undefined) changes.description = description;
        if (price !== undefined) changes.price = formatPrice(price);
        if (categoryId !== undefined) changes.categoryId = categoryId;
        if (imageUrl !== undefined) changes.imageUrl = imageUrl;

        const changeLines = Object.entries(changes)
          .map(([k, v]) => `  ${k}: ${v}`)
          .join("\n");

        return textResponse(
          `Product ${productId} updated successfully.\nUpdated fields:\n${changeLines}`,
        );
      } catch (err) {
        return errorResponse(err);
      }
    },
  );

  // 4. delete_product
  server.tool(
    "delete_product",
    "Deactivate a product from the catalog (soft delete).",
    {
      productId: z.string().uuid().describe("Product ID to deactivate"),
    },
    async ({ productId }) => {
      try {
        await catalogApi.delete(`/products/${productId}`);
        return textResponse(
          `Product ${productId} deactivated successfully.`,
        );
      } catch (err) {
        return errorResponse(err);
      }
    },
  );
}
