/**
 * Competitive Intelligence / Ad Library Tools (Tier 2 - Advanced)
 * Tools for searching Meta Ad Library and analyzing competitor ads
 */

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

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

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

const adTypeSchema = z
  .enum([
    "ALL",
    "POLITICAL_AND_ISSUE_ADS",
    "HOUSING_ADS",
    "EMPLOYMENT_ADS",
    "CREDIT_ADS",
  ])
  .describe("Type of ads to search (ALL for regular ads)");

const adStatusSchema = z
  .enum(["ACTIVE", "INACTIVE", "ALL"])
  .describe("Filter by ad active status");

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

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

  // ============================================================
  // search_ad_library
  // ============================================================
  registry.registerTool({
    name: "search_ad_library",
    description:
      "Search Meta Ad Library for ads by keyword, page, or category",
    inputSchema: z.object({
      search_terms: z
        .string()
        .optional()
        .describe("Keywords to search for in ad content"),
      ad_type: adTypeSchema.optional().describe("Type of ads (default: ALL)"),
      country: z
        .string()
        .describe("Two-letter country code (e.g., 'US', 'GB', 'CA')"),
      search_page_ids: z
        .array(z.string())
        .optional()
        .describe("Array of Page IDs to search ads from"),
      limit: z
        .number()
        .optional()
        .describe("Maximum number of results (default: 50)"),
      fields: z
        .string()
        .optional()
        .describe(
          "Comma-separated fields to return (default: id,ad_creative_bodies,ad_delivery_start_time,page_name)"
        ),
    }),
    annotations: {
      title: "Search Ad Library",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "competitive-intelligence",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          search_terms?: string;
          ad_type?: string;
          country: string;
          search_page_ids?: string[];
          limit?: number;
          fields?: string;
        };

        const queryParams: Record<string, string> = {
          ad_type: params.ad_type || "ALL",
          country: params.country,
          fields:
            params.fields ||
            "id,ad_creation_time,ad_delivery_start_time,ad_delivery_stop_time,ad_creative_bodies,ad_creative_link_captions,ad_creative_link_descriptions,ad_creative_link_titles,page_id,page_name,publisher_platforms,estimated_audience_size,spend,impressions",
        };

        if (params.search_terms) {
          queryParams.search_terms = params.search_terms;
        }

        if (params.search_page_ids && params.search_page_ids.length > 0) {
          queryParams.search_page_ids = JSON.stringify(params.search_page_ids);
        }

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

        // Ad Library uses a special endpoint
        const response = (await client.get("/ads_archive", queryParams)) as {
          data: AdLibraryEntry[];
        };

        const ads = response.data || [];

        const result = {
          ads: ads.map((ad) => ({
            id: ad.id,
            page_id: ad.page_id,
            page_name: ad.page_name,
            created_time: ad.ad_creation_time,
            delivery_start: ad.ad_delivery_start_time,
            delivery_stop: ad.ad_delivery_stop_time,
            is_active: !ad.ad_delivery_stop_time,
            creative: {
              bodies: ad.ad_creative_bodies,
              link_captions: ad.ad_creative_link_captions,
              link_descriptions: ad.ad_creative_link_descriptions,
              link_titles: ad.ad_creative_link_titles,
            },
            platforms: ad.publisher_platforms,
            estimated_audience_size: ad.estimated_audience_size,
            spend_estimate: ad.spend,
            impressions_estimate: ad.impressions,
          })),
          search_terms: params.search_terms,
          country: params.country,
          total_results: ads.length,
          note: "Ad Library data is public information. Spend and audience estimates may not be available for all ads.",
        };

        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_competitor_ads
  // ============================================================
  registry.registerTool({
    name: "get_competitor_ads",
    description: "Get all active ads for a specific Facebook Page",
    inputSchema: z.object({
      page_id: z.string().describe("Facebook Page ID to analyze"),
      ad_status: adStatusSchema
        .optional()
        .describe("Filter by ad status (default: ACTIVE)"),
      limit: z
        .number()
        .optional()
        .describe("Maximum number of ads to return"),
    }),
    annotations: {
      title: "Get Competitor Ads",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "competitive-intelligence",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          page_id: string;
          ad_status?: string;
          limit?: number;
        };

        const queryParams: Record<string, string> = {
          ad_type: "ALL",
          search_page_ids: JSON.stringify([params.page_id]),
          fields:
            "id,ad_creation_time,ad_delivery_start_time,ad_delivery_stop_time,ad_creative_bodies,ad_creative_link_captions,ad_creative_link_descriptions,ad_creative_link_titles,ad_snapshot_url,publisher_platforms,demographic_distribution,delivery_by_region",
        };

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

        // Ad Library search
        const response = (await client.get("/ads_archive", queryParams)) as {
          data: AdLibraryEntry[];
        };

        let ads = response.data || [];

        // Filter by status if specified
        if (params.ad_status === "ACTIVE") {
          ads = ads.filter((ad) => !ad.ad_delivery_stop_time);
        } else if (params.ad_status === "INACTIVE") {
          ads = ads.filter((ad) => !!ad.ad_delivery_stop_time);
        }

        // Analyze ad patterns
        const platforms = new Set<string>();
        const adFormats: Record<string, number> = {};

        ads.forEach((ad) => {
          ad.publisher_platforms?.forEach((platform: string) =>
            platforms.add(platform)
          );

          // Determine format based on creative elements
          if (ad.ad_creative_bodies && ad.ad_creative_bodies.length > 0) {
            const hasVideo = false; // Would need to check actual creative
            const hasImage = true; // Assume image if has body
            const format = hasVideo
              ? "video"
              : hasImage
              ? "image"
              : "text_only";
            adFormats[format] = (adFormats[format] || 0) + 1;
          }
        });

        const result = {
          page_id: params.page_id,
          total_ads: ads.length,
          active_ads: ads.filter((ad) => !ad.ad_delivery_stop_time).length,
          inactive_ads: ads.filter((ad) => !!ad.ad_delivery_stop_time).length,
          platforms_used: Array.from(platforms),
          ad_formats: adFormats,
          ads: ads.map((ad) => ({
            id: ad.id,
            created_time: ad.ad_creation_time,
            delivery_start: ad.ad_delivery_start_time,
            delivery_stop: ad.ad_delivery_stop_time,
            is_active: !ad.ad_delivery_stop_time,
            creative: {
              bodies: ad.ad_creative_bodies,
              link_captions: ad.ad_creative_link_captions,
              link_descriptions: ad.ad_creative_link_descriptions,
              link_titles: ad.ad_creative_link_titles,
            },
            platforms: ad.publisher_platforms,
            demographics: ad.demographic_distribution,
            regions: ad.delivery_by_region,
            snapshot_url: (ad as any).ad_snapshot_url,
          })),
        };

        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_ad_transparency
  // ============================================================
  registry.registerTool({
    name: "get_ad_transparency",
    description:
      "Get page-level advertising transparency data including spend ranges",
    inputSchema: z.object({
      page_id: z.string().describe("Facebook Page ID"),
      country: z
        .string()
        .describe("Two-letter country code for spend data (e.g., 'US')"),
    }),
    annotations: {
      title: "Get Ad Transparency Info",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "competitive-intelligence",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          page_id: string;
          country: string;
        };

        // Search for ads from this page to get aggregate data
        const queryParams: Record<string, string> = {
          ad_type: "ALL",
          search_page_ids: JSON.stringify([params.page_id]),
          country: params.country,
          fields:
            "id,page_name,spend,impressions,ad_delivery_start_time,ad_delivery_stop_time,estimated_audience_size,demographic_distribution,delivery_by_region",
          ad_active_status: "ALL",
          limit: "500",
        };

        const response = (await client.get("/ads_archive", queryParams)) as {
          data: AdLibraryEntry[];
        };

        const ads = response.data || [];

        if (ads.length === 0) {
          return {
            content: [
              {
                type: "text" as const,
                text: JSON.stringify(
                  {
                    page_id: params.page_id,
                    country: params.country,
                    message:
                      "No ad data available for this page in the specified country",
                  },
                  null,
                  2
                ),
              },
            ],
          };
        }

        const pageName = ads[0]?.page_name || "Unknown";

        // Aggregate spend and impressions
        let totalMinSpend = 0;
        let totalMaxSpend = 0;
        let totalMinImpressions = 0;
        let totalMaxImpressions = 0;
        let activeAds = 0;

        const demographics: Record<string, number> = {};
        const regions: Record<string, number> = {};

        ads.forEach((ad) => {
          if (!ad.ad_delivery_stop_time) {
            activeAds++;
          }

          if (ad.spend) {
            totalMinSpend += ad.spend.lower_bound || 0;
            totalMaxSpend += ad.spend.upper_bound || 0;
          }

          if (ad.impressions) {
            totalMinImpressions += ad.impressions.lower_bound || 0;
            totalMaxImpressions += ad.impressions.upper_bound || 0;
          }

          // Aggregate demographics
          ad.demographic_distribution?.forEach((demo: {
            age: string;
            gender: string;
            percentage: string;
          }) => {
            const key = `${demo.age}_${demo.gender}`;
            demographics[key] =
              (demographics[key] || 0) + parseFloat(demo.percentage);
          });

          // Aggregate regions
          ad.delivery_by_region?.forEach((region: {
            region: string;
            percentage: string;
          }) => {
            regions[region.region] =
              (regions[region.region] || 0) + parseFloat(region.percentage);
          });
        });

        // Format demographics
        const topDemographics = Object.entries(demographics)
          .sort(([, a], [, b]) => b - a)
          .slice(0, 10)
          .map(([key, percentage]) => {
            const [age, gender] = key.split("_");
            return { age, gender, percentage };
          });

        // Format regions
        const topRegions = Object.entries(regions)
          .sort(([, a], [, b]) => b - a)
          .slice(0, 10)
          .map(([region, percentage]) => ({ region, percentage }));

        const result = {
          page_id: params.page_id,
          page_name: pageName,
          country: params.country,
          total_ads_found: ads.length,
          active_ads: activeAds,
          estimated_spend: {
            lower_bound: totalMinSpend,
            upper_bound: totalMaxSpend,
            currency: ads[0]?.spend?.currency || "USD",
          },
          estimated_impressions: {
            lower_bound: totalMinImpressions,
            upper_bound: totalMaxImpressions,
          },
          top_demographics: topDemographics,
          top_regions: topRegions,
          note: "Spend and impression data are estimates based on publicly available Ad Library data. Actual values may vary.",
        };

        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,
        };
      }
    },
  });
}
