/**
 * Product Catalog Tools (Tier 2 - Advanced)
 * Tools for managing product catalogs and feeds for dynamic ads
 */

import { z } from "zod";
import type { ToolRegistry } from "../server.js";
import type {
  ProductCatalog,
  Product,
  ToolCategory,
  LoadTier,
} from "../types/meta-api.js";

export const category: ToolCategory = "catalog";
export const tier: LoadTier = "advanced";

// ============================================================
// Shared Schemas
// ============================================================

const productFilterSchema = z
  .object({
    availability: z
      .enum(["in stock", "out of stock", "preorder", "available for order"])
      .optional()
      .describe("Filter by product availability"),
    category: z.string().optional().describe("Filter by product category"),
    brand: z.string().optional().describe("Filter by brand"),
  })
  .optional()
  .describe("Filters for product search");

const productSetFilterSchema = z
  .record(z.unknown())
  .describe(
    "JSON filter rules for product set (e.g., {brand: {eq: 'Nike'}, price: {gt: 50}})"
  );

// ============================================================
// Tool Registration
// ============================================================

export function registerCatalogTools(registry: ToolRegistry): void {
  const client = registry.getClient();

  // ============================================================
  // list_catalogs
  // ============================================================
  registry.registerTool({
    name: "list_catalogs",
    description: "List all product catalogs for a business or ad account",
    inputSchema: z.object({
      business_id: z
        .string()
        .optional()
        .describe("Business ID to list catalogs for"),
      account_id: z
        .string()
        .optional()
        .describe("Ad account ID (alternative to business_id)"),
    }),
    annotations: {
      title: "List Product Catalogs",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "catalogs",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          business_id?: string;
          account_id?: string;
        };

        if (!params.business_id && !params.account_id) {
          throw new Error("Either business_id or account_id must be provided");
        }

        let catalogs: ProductCatalog[];

        if (params.business_id) {
          catalogs = (await client.getAllPages(
            `${params.business_id}/owned_product_catalogs`,
            {
              fields: "id,name,product_count,vertical,business",
            }
          )) as ProductCatalog[];
        } else {
          // Get account first to find business
          const accountId = params.account_id && params.account_id.startsWith("act_")
            ? params.account_id
            : `act_${params.account_id || ''}`;

          const account = (await client.get(accountId, {
            fields: "business",
          })) as { business?: { id: string } };

          if (!account.business) {
            return {
              content: [
                {
                  type: "text" as const,
                  text: JSON.stringify(
                    {
                      catalogs: [],
                      message:
                        "No business associated with this ad account. A Business Manager is required for product catalogs.",
                    },
                    null,
                    2
                  ),
                },
              ],
            };
          }

          catalogs = (await client.getAllPages(
            `${account.business.id}/owned_product_catalogs`,
            {
              fields: "id,name,product_count,vertical,business",
            }
          )) as ProductCatalog[];
        }

        const result = {
          catalogs: catalogs.map((catalog) => ({
            id: catalog.id,
            name: catalog.name,
            product_count: catalog.product_count,
            vertical: catalog.vertical,
            business_id: catalog.business?.id,
            business_name: catalog.business?.name,
          })),
          total_count: catalogs.length,
        };

        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(result, null, 2),
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text" as const,
              text: `Error: ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
          isError: true,
        };
      }
    },
  });

  // ============================================================
  // get_catalog_products
  // ============================================================
  registry.registerTool({
    name: "get_catalog_products",
    description: "Get products from a product catalog with optional filters",
    inputSchema: z.object({
      catalog_id: z.string().describe("Product catalog ID"),
      limit: z
        .number()
        .optional()
        .describe("Maximum number of products to return"),
      filter: productFilterSchema,
    }),
    annotations: {
      title: "Get Catalog Products",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "catalogs",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          catalog_id: string;
          limit?: number;
          filter?: {
            availability?: string;
            category?: string;
            brand?: string;
          };
        };

        const queryParams: Record<string, string> = {
          fields:
            "id,name,description,price,currency,url,image_url,availability,brand,category,retailer_id",
        };

        if (params.limit) {
          queryParams.limit = params.limit.toString();
        }

        // Build filtering query
        const filters: Array<{
          field: string;
          operator: string;
          value: string;
        }> = [];

        if (params.filter?.availability) {
          filters.push({
            field: "availability",
            operator: "EQUAL",
            value: params.filter.availability,
          });
        }

        if (params.filter?.category) {
          filters.push({
            field: "category",
            operator: "EQUAL",
            value: params.filter.category,
          });
        }

        if (params.filter?.brand) {
          filters.push({
            field: "brand",
            operator: "EQUAL",
            value: params.filter.brand,
          });
        }

        if (filters.length > 0) {
          queryParams.filter = JSON.stringify(filters);
        }

        const products = (await client.getAllPages(
          `${params.catalog_id}/products`,
          queryParams
        )) as Product[];

        const result = {
          products: products.map((product) => ({
            id: product.id,
            name: product.name,
            description: product.description,
            price: parseFloat(product.price),
            currency: product.currency,
            url: product.url,
            image_url: product.image_url,
            availability: product.availability,
            brand: product.brand,
            category: product.category,
            retailer_id: product.retailer_id,
          })),
          catalog_id: params.catalog_id,
          total_count: products.length,
          filters_applied: params.filter,
        };

        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(result, null, 2),
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text" as const,
              text: `Error: ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
          isError: true,
        };
      }
    },
  });

  // ============================================================
  // create_product_set
  // ============================================================
  registry.registerTool({
    name: "create_product_set",
    description: "Create a filtered product set for use in dynamic ads",
    inputSchema: z.object({
      catalog_id: z.string().describe("Product catalog ID"),
      name: z.string().describe("Name for the product set"),
      filter: productSetFilterSchema.describe(
        "Filter rules to define which products are included"
      ),
    }),
    annotations: {
      title: "Create Product Set",
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: false,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "catalogs",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          catalog_id: string;
          name: string;
          filter: Record<string, unknown>;
        };

        const productSetData: Record<string, unknown> = {
          name: params.name,
          filter: params.filter,
        };

        const response = (await client.post(
          `${params.catalog_id}/product_sets`,
          productSetData
        )) as { id: string };

        const result = {
          product_set_id: response.id,
          catalog_id: params.catalog_id,
          name: params.name,
          filter: params.filter,
          message: "Product set created successfully",
        };

        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(result, null, 2),
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text" as const,
              text: `Error: ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
          isError: true,
        };
      }
    },
  });

  // ============================================================
  // get_catalog_diagnostics
  // ============================================================
  registry.registerTool({
    name: "get_catalog_diagnostics",
    description: "Get product catalog feed health, errors, and warnings",
    inputSchema: z.object({
      catalog_id: z.string().describe("Product catalog ID"),
    }),
    annotations: {
      title: "Get Catalog Diagnostics",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "catalogs",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          catalog_id: string;
        };

        // Get catalog info
        const catalog = (await client.get(params.catalog_id, {
          fields: "id,name,product_count,vertical",
        })) as ProductCatalog;

        // Get diagnostics from product feeds
        const diagnostics = (await client.get(
          `${params.catalog_id}/product_feeds`,
          {
            fields:
              "id,name,latest_upload{id,start_time,end_time,num_persisted_products,num_rejected_products,num_detected_products,errors,warnings}",
          }
        )) as {
          data: Array<{
            id: string;
            name: string;
            latest_upload?: {
              id: string;
              start_time: string;
              end_time: string;
              num_persisted_products: number;
              num_rejected_products: number;
              num_detected_products: number;
              errors?: Array<{
                severity: string;
                description: string;
                summary: string;
                error_count: number;
                samples?: Array<{
                  id: string;
                  retailer_id: string;
                  row_number: number;
                }>;
              }>;
              warnings?: Array<{
                severity: string;
                description: string;
                summary: string;
                warning_count: number;
              }>;
            };
          }>;
        };

        const feeds = diagnostics.data || [];

        // Aggregate diagnostics
        const totalErrors = feeds.reduce(
          (sum, feed) => sum + (feed.latest_upload?.errors?.length || 0),
          0
        );
        const totalWarnings = feeds.reduce(
          (sum, feed) => sum + (feed.latest_upload?.warnings?.length || 0),
          0
        );
        const totalRejected = feeds.reduce(
          (sum, feed) =>
            sum + (feed.latest_upload?.num_rejected_products || 0),
          0
        );
        const totalPersisted = feeds.reduce(
          (sum, feed) =>
            sum + (feed.latest_upload?.num_persisted_products || 0),
          0
        );

        const result = {
          catalog_id: params.catalog_id,
          catalog_name: catalog.name,
          product_count: catalog.product_count,
          health_summary: {
            total_errors: totalErrors,
            total_warnings: totalWarnings,
            products_rejected: totalRejected,
            products_persisted: totalPersisted,
            success_rate:
              totalPersisted + totalRejected > 0
                ? (totalPersisted / (totalPersisted + totalRejected)) * 100
                : 0,
          },
          feeds: feeds.map((feed) => ({
            feed_id: feed.id,
            feed_name: feed.name,
            latest_upload: feed.latest_upload
              ? {
                  upload_id: feed.latest_upload.id,
                  start_time: feed.latest_upload.start_time,
                  end_time: feed.latest_upload.end_time,
                  products_detected: feed.latest_upload.num_detected_products,
                  products_persisted:
                    feed.latest_upload.num_persisted_products,
                  products_rejected: feed.latest_upload.num_rejected_products,
                  errors: feed.latest_upload.errors?.map((err) => ({
                    severity: err.severity,
                    description: err.description,
                    summary: err.summary,
                    count: err.error_count,
                    samples: err.samples?.slice(0, 5), // Limit to 5 samples
                  })),
                  warnings: feed.latest_upload.warnings?.map((warn) => ({
                    severity: warn.severity,
                    description: warn.description,
                    summary: warn.summary,
                    count: warn.warning_count,
                  })),
                }
              : null,
          })),
        };

        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(result, null, 2),
            },
          ],
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text" as const,
              text: `Error: ${error instanceof Error ? error.message : String(error)}`,
            },
          ],
          isError: true,
        };
      }
    },
  });
}
