/**
 * Audience Management Tools (Tier 2 - Advanced)
 * Tools for managing custom audiences, lookalikes, and targeting
 */

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

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

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

const audienceSubtypeSchema = z
  .enum([
    "CUSTOM",
    "WEBSITE",
    "APP",
    "OFFLINE",
    "CLAIM",
    "PARTNER",
    "MANAGED",
    "VIDEO",
    "LOOKALIKE",
    "ENGAGEMENT",
    "BAG_OF_ACCOUNTS",
    "STUDY_RULE_AUDIENCE",
    "FOX",
  ])
  .describe("Type of custom audience");

const targetingSpecSchema = z
  .record(z.unknown())
  .describe("Targeting specification object (JSON)");

const interestTypeSchema = z
  .enum(["interest", "behavior", "education", "work", "life_event"])
  .describe("Type of targeting criteria to search");

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

export function registerAudienceTools(registry: ToolRegistry): void {
  const client = registry.getClient();
  
  // ============================================================
  // list_audiences
  // ============================================================
  registry.registerTool({
    name: "list_audiences",
    description: "List all custom and saved audiences for an ad account",
    inputSchema: z.object({
      account_id: z
        .string()
        .describe("Ad account ID (with or without act_ prefix)"),
      limit: z.number().optional().describe("Maximum number of results"),
      subtype: audienceSubtypeSchema
        .optional()
        .describe("Filter by audience subtype"),
    }),
    annotations: {
      title: "List Audiences",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as { account_id: string; limit?: number; subtype?: CustomAudienceSubtype };
        const accountId = params.account_id.startsWith("act_")
          ? params.account_id
          : `act_${params.account_id}`;

        const queryParams: Record<string, string> = {
          fields:
            "id,name,subtype,description,approximate_count_lower_bound,approximate_count_upper_bound,time_created,time_updated,retention_days,delivery_status,operation_status",
        };

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

        if (params.subtype) {
          queryParams.filtering = JSON.stringify([
            {
              field: "subtype",
              operator: "EQUAL",
              value: params.subtype,
            },
          ]);
        }

        const audiences = await client.getAllPages<CustomAudience>(
          `${accountId}/customaudiences`,
          queryParams
        );

        const result = {
          audiences: audiences.map((audience) => ({
            id: audience.id,
            name: audience.name,
            subtype: audience.subtype,
            description: audience.description,
            size_range: {
              lower: audience.approximate_count_lower_bound,
              upper: audience.approximate_count_upper_bound,
            },
            created: audience.time_created,
            updated: audience.time_updated,
            status: audience.delivery_status?.status,
          })),
          account_id: accountId,
          total_count: audiences.length,
        };

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

  // ============================================================
  // create_custom_audience
  // ============================================================
  registry.registerTool({
    name: "create_custom_audience",
    description: "Create a new custom audience from rules or data",
    inputSchema: z.object({
      account_id: z
        .string()
        .describe("Ad account ID (with or without act_ prefix)"),
      name: z.string().describe("Name for the custom audience"),
      description: z.string().optional().describe("Audience description"),
      subtype: audienceSubtypeSchema.describe(
        "Type of custom audience to create"
      ),
      rule: z
        .string()
        .optional()
        .describe("Rule definition (JSON string for rule-based audiences)"),
      retention_days: z
        .number()
        .optional()
        .describe("Number of days to keep users in audience (1-180)"),
      customer_file_source: z
        .string()
        .optional()
        .describe(
          "Source identifier for customer list uploads (USER_PROVIDED_ONLY or PARTNER_PROVIDED_ONLY)"
        ),
    }),
    annotations: {
      title: "Create Custom Audience",
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: false,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          account_id: string;
          name: string;
          description?: string;
          subtype: CustomAudienceSubtype;
          rule?: string;
          retention_days?: number;
          customer_file_source?: string;
        };
        
        const accountId = params.account_id.startsWith("act_")
          ? params.account_id
          : `act_${params.account_id}`;

        const audienceData: Record<string, unknown> = {
          name: params.name,
          subtype: params.subtype,
        };

        if (params.description) {
          audienceData.description = params.description;
        }

        if (params.rule) {
          audienceData.rule = params.rule;
        }

        if (params.retention_days) {
          audienceData.retention_days = params.retention_days;
        }

        if (params.customer_file_source) {
          audienceData.customer_file_source = params.customer_file_source;
        }

        const response = await client.post<{ id: string }>(
          `${accountId}/customaudiences`,
          audienceData
        );

        const result = {
          audience_id: response.id,
          name: params.name,
          subtype: params.subtype,
          message: "Custom audience created successfully",
        };

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

  // ============================================================
  // create_lookalike
  // ============================================================
  registry.registerTool({
    name: "create_lookalike",
    description: "Create a lookalike audience from a source audience",
    inputSchema: z.object({
      account_id: z
        .string()
        .describe("Ad account ID (with or without act_ prefix)"),
      name: z.string().describe("Name for the lookalike audience"),
      origin_audience_id: z
        .string()
        .describe("Source custom audience ID to base lookalike on"),
      ratio: z
        .number()
        .min(0.01)
        .max(0.2)
        .describe(
          "Lookalike size as percentage (0.01 = 1%, 0.1 = 10%, 0.2 = 20%)"
        ),
      countries: z
        .array(z.string())
        .describe("Array of country codes (e.g., ['US', 'CA', 'GB'])"),
      lookalike_type: z
        .enum(["similarity", "reach"])
        .optional()
        .describe("Balance between similarity vs reach (default: similarity)"),
    }),
    annotations: {
      title: "Create Lookalike Audience",
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: false,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          account_id: string;
          name: string;
          origin_audience_id: string;
          ratio: number;
          countries: string[];
          lookalike_type?: "similarity" | "reach";
        };
        
        const accountId = params.account_id.startsWith("act_")
          ? params.account_id
          : `act_${params.account_id}`;

        const lookalikeData: Record<string, unknown> = {
          name: params.name,
          subtype: "LOOKALIKE",
          lookalike_spec: {
            origin: [
              {
                id: params.origin_audience_id,
              },
            ],
            ratio: params.ratio,
            country: params.countries.join(","),
            type: params.lookalike_type || "similarity",
          },
        };

        const response = await client.post<{ id: string }>(
          `${accountId}/customaudiences`,
          lookalikeData
        );

        const result = {
          audience_id: response.id,
          name: params.name,
          origin_audience_id: params.origin_audience_id,
          ratio: params.ratio,
          countries: params.countries,
          message: "Lookalike audience created successfully",
        };

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

  // ============================================================
  // estimate_audience_size
  // ============================================================
  registry.registerTool({
    name: "estimate_audience_size",
    description: "Get estimated audience size for a targeting specification",
    inputSchema: z.object({
      account_id: z
        .string()
        .describe("Ad account ID (with or without act_ prefix)"),
      targeting_spec: targetingSpecSchema.describe(
        "Full targeting specification to estimate"
      ),
    }),
    annotations: {
      title: "Estimate Audience Size",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          account_id: string;
          targeting_spec: Record<string, unknown>;
        };
        
        const accountId = params.account_id.startsWith("act_")
          ? params.account_id
          : `act_${params.account_id}`;

        const response = await client.get<{
          data: Array<{
            estimate_dau: number;
            estimate_mau_lower_bound: number;
            estimate_mau_upper_bound: number;
            estimate_ready: boolean;
          }>;
        }>(`${accountId}/reachestimate`, {
          targeting_spec: JSON.stringify(params.targeting_spec),
        });

        const estimate = response.data[0];

        const result = {
          estimated_daily_active_users: estimate?.estimate_dau || 0,
          estimated_monthly_users: {
            lower_bound: estimate?.estimate_mau_lower_bound || 0,
            upper_bound: estimate?.estimate_mau_upper_bound || 0,
          },
          estimate_ready: estimate?.estimate_ready || false,
          account_id: accountId,
        };

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

  // ============================================================
  // get_targeting_suggestions
  // ============================================================
  registry.registerTool({
    name: "get_targeting_suggestions",
    description: "Get AI-powered targeting suggestions to expand or refine your audience",
    inputSchema: z.object({
      account_id: z
        .string()
        .describe("Ad account ID (with or without act_ prefix)"),
      targeting_list: z
        .array(z.string())
        .describe("Current interest/behavior IDs for suggestions"),
      optimization_goal: z
        .string()
        .optional()
        .describe("Campaign optimization goal to optimize suggestions for"),
    }),
    annotations: {
      title: "Get Targeting Suggestions",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          account_id: string;
          targeting_list: string[];
          optimization_goal?: string;
        };
        
        const accountId = params.account_id.startsWith("act_")
          ? params.account_id
          : `act_${params.account_id}`;

        const queryParams: Record<string, string> = {
          interest_list: JSON.stringify(params.targeting_list),
        };

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

        const response = await client.get<{
          data: Array<{
            id: string;
            name: string;
            type: string;
            audience_size_lower_bound?: number;
            audience_size_upper_bound?: number;
            path?: string[];
            description?: string;
          }>;
        }>(`${accountId}/targetingsuggestions`, queryParams);

        const result = {
          suggestions: response.data.map((suggestion) => ({
            id: suggestion.id,
            name: suggestion.name,
            type: suggestion.type,
            estimated_size: {
              lower: suggestion.audience_size_lower_bound,
              upper: suggestion.audience_size_upper_bound,
            },
            path: suggestion.path,
            description: suggestion.description,
          })),
          account_id: accountId,
          total_suggestions: response.data.length,
        };

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

  // ============================================================
  // search_interests
  // ============================================================
  registry.registerTool({
    name: "search_interests",
    description: "Search for available interests, behaviors, demographics, and life events",
    inputSchema: z.object({
      query: z.string().describe("Search query (e.g., 'fitness', 'travel')"),
      type: interestTypeSchema
        .optional()
        .describe("Filter by targeting type"),
      limit: z
        .number()
        .optional()
        .describe("Maximum number of results (default: 50)"),
    }),
    annotations: {
      title: "Search Interests",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: true,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          query: string;
          type?: "interest" | "behavior" | "education" | "work" | "life_event";
          limit?: number;
        };
        
        const queryParams: Record<string, string> = {
          q: params.query,
          type: "adinterest",
        };

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

        if (params.type) {
          queryParams.class = params.type;
        }

        const response = await client.get<{
          data: Array<{
            id: string;
            name: string;
            audience_size_lower_bound?: number;
            audience_size_upper_bound?: number;
            path?: string[];
            description?: string;
            topic?: string;
          }>;
        }>("/search", queryParams);

        const result = {
          results: response.data.map((item) => ({
            id: item.id,
            name: item.name,
            estimated_size: {
              lower: item.audience_size_lower_bound,
              upper: item.audience_size_upper_bound,
            },
            path: item.path,
            description: item.description,
            topic: item.topic,
          })),
          query: params.query,
          total_results: response.data.length,
        };

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

  // ============================================================
  // get_audience_overlap
  // ============================================================
  registry.registerTool({
    name: "get_audience_overlap",
    description: "Calculate the overlap percentage between two custom audiences",
    inputSchema: z.object({
      audience_id_1: z.string().describe("First audience ID"),
      audience_id_2: z.string().describe("Second audience ID"),
    }),
    annotations: {
      title: "Get Audience Overlap",
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "audiences",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as {
          audience_id_1: string;
          audience_id_2: string;
        };
        
        // Get audience details for both
        const [audience1, audience2] = await Promise.all([
          client.get<CustomAudience>(params.audience_id_1, {
            fields:
              "id,name,approximate_count_lower_bound,approximate_count_upper_bound",
          }),
          client.get<CustomAudience>(params.audience_id_2, {
            fields:
              "id,name,approximate_count_lower_bound,approximate_count_upper_bound",
          }),
        ]);

        // Calculate overlap using the overlap edge
        const overlapResponse = await client.get<{
          data: Array<{
            overlap_count_lower_bound: number;
            overlap_count_upper_bound: number;
          }>;
        }>(`${params.audience_id_1}/`, {
          fields: "overlap",
          custom_audience_id: params.audience_id_2,
        });

        const overlapData = overlapResponse.data[0];

        // Calculate percentages
        const audience1Size =
          (audience1.approximate_count_lower_bound || 0) +
          (audience1.approximate_count_upper_bound || 0);
        const audience2Size =
          (audience2.approximate_count_lower_bound || 0) +
          (audience2.approximate_count_upper_bound || 0);
        const overlapSize =
          (overlapData?.overlap_count_lower_bound || 0) +
          (overlapData?.overlap_count_upper_bound || 0);

        const overlapPercentage1 =
          audience1Size > 0 ? (overlapSize / audience1Size) * 100 : 0;
        const overlapPercentage2 =
          audience2Size > 0 ? (overlapSize / audience2Size) * 100 : 0;

        const result = {
          audience_1: {
            id: audience1.id,
            name: audience1.name,
            size_estimate: {
              lower: audience1.approximate_count_lower_bound,
              upper: audience1.approximate_count_upper_bound,
            },
          },
          audience_2: {
            id: audience2.id,
            name: audience2.name,
            size_estimate: {
              lower: audience2.approximate_count_lower_bound,
              upper: audience2.approximate_count_upper_bound,
            },
          },
          overlap: {
            count_estimate: {
              lower: overlapData?.overlap_count_lower_bound,
              upper: overlapData?.overlap_count_upper_bound,
            },
            percentage_of_audience_1: overlapPercentage1,
            percentage_of_audience_2: overlapPercentage2,
          },
        };

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