import { z } from 'zod';
import type { ToolRegistry } from '../server.js';
import type {
  AdSet,
  AdSetStatus,
  TargetingSpec,
  MetaPaginatedResponse,
  CreateAdSetParams,
  UpdateAdSetParams,
} from '../types/meta-api.js';

/**
 * Register ad set management tools
 */
export function registerAdSetTools(registry: ToolRegistry): void {
  const client = registry.getClient();

  // List ad sets
  registry.registerTool({
    name: 'list_ad_sets',
    description: 'List ad sets by account or campaign with optional status filters',
    inputSchema: z.object({
      parent_id: z.string().describe('Parent ID: ad account (act_XXXXX) or campaign ID'),
      parent_type: z.enum(['account', 'campaign']).describe('Whether parent_id is an account or campaign'),
      status: z.enum(['ACTIVE', 'PAUSED', 'DELETED', 'ARCHIVED']).optional().describe('Filter by ad set status'),
      limit: z.number().optional().describe('Maximum number of ad sets to return (default: 100)'),
    }),
    annotations: {
      title: 'List Ad Sets',
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const { parent_id, parent_type, status, limit } = args as {
          parent_id: string;
          parent_type: 'account' | 'campaign';
          status?: AdSetStatus;
          limit?: number;
        };
        
        const params: Record<string, unknown> = {
          fields: 'id,name,campaign_id,status,effective_status,optimization_goal,billing_event,bid_amount,bid_strategy,daily_budget,lifetime_budget,budget_remaining,start_time,end_time,created_time,updated_time,targeting',
          limit: limit || 100,
        };

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

        const endpoint = parent_type === 'account' ? `${parent_id}/adsets` : `${parent_id}/adsets`;
        const response = await client.get<MetaPaginatedResponse<AdSet>>(endpoint, params);

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

  // Get ad set
  registry.registerTool({
    name: 'get_ad_set',
    description: 'Get full ad set details including targeting configuration',
    inputSchema: z.object({
      adset_id: z.string().describe('Ad set ID'),
    }),
    annotations: {
      title: 'Get Ad Set',
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "read",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const { adset_id } = args as { adset_id: string };
        
        const adset = await client.get<AdSet>(adset_id, {
          fields: 'id,name,account_id,campaign_id,status,effective_status,optimization_goal,billing_event,bid_amount,bid_strategy,daily_budget,lifetime_budget,budget_remaining,targeting,start_time,end_time,created_time,updated_time,promoted_object,destination_type',
        });

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

  // Create ad set
  registry.registerTool({
    name: 'create_ad_set',
    description: 'Create a new ad set with targeting, budget, schedule, placements, and optimization goal',
    inputSchema: z.object({
      campaign_id: z.string().describe('Parent campaign ID'),
      name: z.string().describe('Ad set name'),
      optimization_goal: z.string().describe('Optimization goal (e.g., LINK_CLICKS, CONVERSIONS, REACH)'),
      billing_event: z.string().describe('Billing event (e.g., IMPRESSIONS, LINK_CLICKS)'),
      daily_budget: z.string().optional().describe('Daily budget in cents (e.g., "2000" for $20)'),
      lifetime_budget: z.string().optional().describe('Lifetime budget in cents'),
      bid_amount: z.number().optional().describe('Bid amount in cents'),
      status: z.enum(['ACTIVE', 'PAUSED']).optional().describe('Initial status (default: PAUSED)'),
      start_time: z.string().optional().describe('Start time in ISO 8601 format'),
      end_time: z.string().optional().describe('End time in ISO 8601 format'),
      targeting: z.object({
        age_min: z.number().optional(),
        age_max: z.number().optional(),
        genders: z.array(z.number()).optional(),
        geo_locations: z.object({
          countries: z.array(z.string()).optional(),
          regions: z.array(z.object({ key: z.string() })).optional(),
          cities: z.array(z.object({ key: z.string(), radius: z.number().optional(), distance_unit: z.string().optional() })).optional(),
        }).optional(),
        publisher_platforms: z.array(z.string()).optional(),
        facebook_positions: z.array(z.string()).optional(),
        instagram_positions: z.array(z.string()).optional(),
        device_platforms: z.array(z.string()).optional(),
        locales: z.array(z.number()).optional(),
      }).describe('Targeting specification'),
    }),
    annotations: {
      title: 'Create Ad Set',
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: false,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "write",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const params = args as unknown as CreateAdSetParams;
        
        const response = await client.post<{ id: string }>(
          `act_${params.campaign_id.split('_')[1]}/adsets`, // Extract account from campaign
          params as unknown as Record<string, unknown>
        );

        return {
          content: [{
            type: 'text',
            text: `Ad set created successfully: ${response.id}`,
          }],
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `Error: ${error instanceof Error ? error.message : String(error)}`,
          }],
          isError: true,
        };
      }
    },
  });

  // Update targeting
  registry.registerTool({
    name: 'update_targeting',
    description: 'Modify audience targeting on an ad set (demographics, locations, interests, etc.)',
    inputSchema: z.object({
      adset_id: z.string().describe('Ad set ID'),
      targeting: z.object({
        age_min: z.number().optional(),
        age_max: z.number().optional(),
        genders: z.array(z.number()).optional(),
        geo_locations: z.object({
          countries: z.array(z.string()).optional(),
          regions: z.array(z.object({ key: z.string() })).optional(),
        }).optional(),
        interests: z.array(z.object({ id: z.string(), name: z.string() })).optional(),
        behaviors: z.array(z.object({ id: z.string(), name: z.string() })).optional(),
        custom_audiences: z.array(z.object({ id: z.string() })).optional(),
      }).describe('Updated targeting specification'),
    }),
    annotations: {
      title: 'Update Targeting',
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "write",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const { adset_id, targeting } = args as { adset_id: string; targeting: TargetingSpec };
        
        await client.post<{ success: boolean }>(adset_id, { targeting });

        return {
          content: [{
            type: 'text',
            text: `Targeting updated successfully for ad set ${adset_id}`,
          }],
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `Error: ${error instanceof Error ? error.message : String(error)}`,
          }],
          isError: true,
        };
      }
    },
  });

  // Update ad set budget
  registry.registerTool({
    name: 'update_ad_set_budget',
    description: 'Change budget and bid strategy for an ad set',
    inputSchema: z.object({
      adset_id: z.string().describe('Ad set ID'),
      daily_budget: z.string().optional().describe('Daily budget in cents'),
      lifetime_budget: z.string().optional().describe('Lifetime budget in cents'),
      bid_amount: z.number().optional().describe('Bid amount in cents'),
      bid_strategy: z.enum(['LOWEST_COST_WITHOUT_CAP', 'LOWEST_COST_WITH_BID_CAP', 'COST_CAP', 'LOWEST_COST_WITH_MIN_ROAS']).optional().describe('Bid strategy'),
    }),
    annotations: {
      title: 'Update Ad Set Budget',
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "write",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const { adset_id, ...budgetParams } = args as unknown as UpdateAdSetParams & { adset_id: string };
        
        await client.post<{ success: boolean }>(adset_id, budgetParams as Record<string, unknown>);

        return {
          content: [{
            type: 'text',
            text: `Budget updated successfully for ad set ${adset_id}`,
          }],
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `Error: ${error instanceof Error ? error.message : String(error)}`,
          }],
          isError: true,
        };
      }
    },
  });

  // Update schedule
  registry.registerTool({
    name: 'update_schedule',
    description: 'Modify flight dates (start and end time) for an ad set',
    inputSchema: z.object({
      adset_id: z.string().describe('Ad set ID'),
      start_time: z.string().optional().describe('Start time in ISO 8601 format'),
      end_time: z.string().optional().describe('End time in ISO 8601 format'),
    }),
    annotations: {
      title: 'Update Schedule',
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "write",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const { adset_id, start_time, end_time } = args as {
          adset_id: string;
          start_time?: string;
          end_time?: string;
        };
        
        const params: Record<string, unknown> = {};
        if (start_time) params.start_time = start_time;
        if (end_time) params.end_time = end_time;

        await client.post<{ success: boolean }>(adset_id, params);

        return {
          content: [{
            type: 'text',
            text: `Schedule updated successfully for ad set ${adset_id}`,
          }],
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `Error: ${error instanceof Error ? error.message : String(error)}`,
          }],
          isError: true,
        };
      }
    },
  });

  // Toggle ad set
  registry.registerTool({
    name: 'toggle_ad_set',
    description: 'Pause or resume an ad set',
    inputSchema: z.object({
      adset_id: z.string().describe('Ad set ID'),
      status: z.enum(['ACTIVE', 'PAUSED']).describe('Target status: ACTIVE to resume, PAUSED to pause'),
    }),
    annotations: {
      title: 'Toggle Ad Set',
      readOnlyHint: false,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false,
    },
    _meta: {
      labels: {
        category: "ad-sets",
        access: "write",
        complexity: "simple"
      }
    },
    handler: async (args) => {
      try {
        const { adset_id, status } = args as { adset_id: string; status: 'ACTIVE' | 'PAUSED' };
        
        await client.post<{ success: boolean }>(adset_id, { status });

        return {
          content: [{
            type: 'text',
            text: `Ad set ${adset_id} ${status === 'ACTIVE' ? 'resumed' : 'paused'} successfully`,
          }],
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `Error: ${error instanceof Error ? error.message : String(error)}`,
          }],
          isError: true,
        };
      }
    },
  });
}
