import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import { platformFetch } from '../../lib/platform-client.js';

const metricTypeSchema = z.enum(['conversion', 'count', 'duration', 'revenue', 'custom']);

registerTool({
  name: 'experiments.create',
  description:
    'Create a new A/B experiment with variants and targeting criteria. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID for the experiment'),
    key: z
      .string()
      .min(1)
      .describe('Unique slug/key for the experiment (e.g., onboarding_flow_v2)'),
    name: z.string().min(1).describe('Human-readable experiment name'),
    description: z.string().optional().describe('Experiment description'),
    variants: z
      .array(
        z.object({
          key: z.string().min(1),
          weight: z.number().int().min(0).max(100),
          description: z.string(),
        })
      )
      .min(2)
      .describe('At least 2 variants (control + treatment)'),
    targetSegments: z.array(z.string()).optional().describe('Optional user segments to target'),
    trafficPercent: z
      .number()
      .int()
      .min(1)
      .max(100)
      .default(10)
      .describe('Percentage of eligible users to enroll'),
    hypothesis: z.string().optional().describe('Experiment hypothesis'),
    primaryMetric: z.string().min(1).describe('Primary success metric (e.g., conversion_rate)'),
  }),
  async execute(args, req) {
    const {
      productId,
      key,
      name,
      description,
      variants,
      targetSegments,
      trafficPercent,
      hypothesis,
      primaryMetric,
    } = args;

    const experiment = {
      name,
      description: description ?? '',
      hypothesis: hypothesis ?? `Test whether ${name} improves ${primaryMetric} for ${productId}`,
      variants: variants.map(
        (variant: { key: string; weight: number; description: string }, index: number) => ({
          key: variant.key,
          name: variant.key,
          description: variant.description,
          isControl: index === 0 || variant.key === 'control',
          flagConfig: {
            key,
            variantKey: variant.key,
          },
        })
      ),
      allocationStrategy: 'random' as const,
      targetPercent: trafficPercent,
      targeting: targetSegments?.length ? { userSegments: targetSegments } : {},
      primaryMetric: {
        name: primaryMetric,
        type: 'conversion' as const,
        eventName: primaryMetric,
        aggregation: 'count' as const,
        direction: 'increase' as const,
        minimumDetectableEffect: 5,
      },
      secondaryMetrics: [],
      guardrails: {
        minSampleSizePerVariant: 100,
        maxDurationDays: 30,
        autoStopEnabled: true,
        winnerThreshold: 95,
        requireApprovalFor: 'none' as const,
      },
    };

    const response = await platformFetch<{ id: string; status: string }>(
      '/api/ab-testing/experiments',
      {
        method: 'POST',
        body: JSON.stringify(experiment),
      },
      {
        token: req.headers.authorization?.replace('Bearer ', '') || '',
        requestId: req.id,
        productId,
      }
    );

    return {
      experimentId: response.id,
      productId,
      key,
      name,
      status: response.status,
      summary: `Created experiment "${name}" with ${variants.length} variants for ${productId}`,
    };
  },
});

registerTool({
  name: 'experiments.start',
  description: 'Start a draft experiment (changes status to running). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    experimentId: z.string().min(1).describe('Experiment ID to start'),
  }),
  async execute(args, req) {
    const { experimentId } = args;

    const response = await platformFetch<{ id: string; name: string; status: string }>(
      `/api/ab-testing/experiments/${experimentId}/start`,
      { method: 'POST' },
      { token: req.headers.authorization?.replace('Bearer ', '') || '', requestId: req.id }
    );

    return {
      experimentId: response.id,
      name: response.name,
      status: response.status,
      summary: `Started experiment "${response.name}"`,
    };
  },
});

registerTool({
  name: 'experiments.list',
  description:
    'List experiments with optional filtering by product and status. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().optional().describe('Filter by product ID'),
    status: z
      .enum(['draft', 'running', 'paused', 'completed'])
      .optional()
      .describe('Filter by status'),
    limit: z
      .number()
      .int()
      .min(1)
      .max(100)
      .default(20)
      .describe('Maximum number of experiments to return'),
  }),
  async execute(args, req) {
    const { productId, status, limit } = args;

    const params = new URLSearchParams();
    if (productId) params.set('productId', productId);
    if (status) params.set('status', status);
    params.set('limit', limit.toString());

    const response = await platformFetch<
      Array<{
        id: string;
        name: string;
        description: string;
        status: string;
        targetPercent: number;
        createdAt: string;
        startedAt?: string;
        completedAt?: string;
      }>
    >(
      '/api/ab-testing/experiments',
      { method: 'GET' },
      {
        token: req.headers.authorization?.replace('Bearer ', '') || '',
        requestId: req.id,
        productId,
      }
    );

    const experiments = response
      .filter(experiment => (status ? experiment.status === status : true))
      .slice(0, limit);

    return {
      experiments,
      total: experiments.length,
      filters: { productId, status, limit },
      summary: `Found ${experiments.length} experiments matching criteria`,
    };
  },
});

registerTool({
  name: 'experiments.getResults',
  description:
    'Get statistical results and performance metrics for an experiment. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    experimentId: z.string().min(1).describe('Experiment ID'),
    confidenceLevel: z
      .number()
      .min(0.8)
      .max(0.99)
      .default(0.95)
      .describe('Statistical confidence level (0.8-0.99)'),
  }),
  async execute(args, req) {
    const { experimentId, confidenceLevel } = args;

    const response = await platformFetch<{
      experimentId: string;
      status: string;
      totalParticipants: number;
      totalEvents: number;
      daysRunning: number;
      winnerVariantId?: string;
      winnerProbability?: number;
      variantResults: Array<{
        variantId: string;
        variantName: string;
        isControl: boolean;
        participants: number;
        primaryMetricValue: number;
        probabilityBeatsControl: number;
        expectedLiftPercent: number;
        credibleInterval: { lower: number; mean: number; upper: number };
      }>;
      statisticalSummary: {
        probabilityAnyBeatsControl: number;
        expectedLossIfShipped: number;
        recommendedAction: 'ship' | 'rollback' | 'continue' | 'stop';
      };
    }>(
      `/api/ab-testing/experiments/${experimentId}/results`,
      { method: 'GET' },
      { token: req.headers.authorization?.replace('Bearer ', '') || '', requestId: req.id }
    );

    return {
      results: response,
      confidenceLevel,
      summary: `Results for ${response.experimentId}: ${response.statisticalSummary.recommendedAction} after ${response.totalParticipants} participants`,
    };
  },
});

registerTool({
  name: 'experiments.assignVariant',
  description:
    'Get the variant assignment for a specific user in an experiment. Requires viewer role.',
  requiredRole: 'viewer',
  inputSchema: z.object({
    experimentKey: z.string().min(1).describe('Experiment key (slug)'),
    context: z.record(z.unknown()).optional().describe('Optional user context for targeting'),
  }),
  async execute(args, req) {
    const { experimentKey, context } = args;

    const response = await platformFetch<{
      assigned: boolean;
      reason?: string;
      experimentId?: string;
      variantId?: string;
      variantName?: string;
      isControl?: boolean;
      flagConfig?: Record<string, unknown>;
      isNew?: boolean;
    }>(
      '/api/ab-testing/assign',
      {
        method: 'POST',
        body: JSON.stringify({ experimentKey, context }),
      },
      { token: req.headers.authorization?.replace('Bearer ', '') || '', requestId: req.id }
    );

    return {
      experimentKey,
      assigned: response.assigned,
      reason: response.reason,
      experimentId: response.experimentId,
      variantId: response.variantId,
      variantName: response.variantName,
      isControl: response.isControl,
      flagConfig: response.flagConfig,
      isNew: response.isNew,
      summary: response.assigned
        ? `User assigned to variant "${response.variantName}"`
        : `User not enrolled: ${response.reason}`,
    };
  },
});

registerTool({
  name: 'experiments.trackEvent',
  description:
    'Track an event for a user in an experiment (conversion, retention, etc.). Requires viewer role.',
  requiredRole: 'viewer',
  inputSchema: z.object({
    experimentId: z.string().min(1).describe('Experiment ID'),
    userId: z.string().min(1).describe('User ID'),
    metricType: metricTypeSchema.describe('Metric type'),
    metricName: z.string().min(1).describe('Metric/event name'),
    value: z.number().describe('Numeric value for the event'),
    platform: z.string().optional().describe('Platform context (web, ios, android)'),
    appVersion: z.string().optional().describe('App version context'),
    metadata: z.record(z.unknown()).optional().describe('Additional event metadata'),
  }),
  async execute(args, req) {
    const { experimentId, userId, metricType, metricName, value, platform, appVersion, metadata } =
      args;

    const response = await platformFetch<{
      tracked: boolean;
    }>(
      '/api/ab-testing/events',
      {
        method: 'POST',
        body: JSON.stringify({
          experimentId,
          userId,
          metricType,
          metricName,
          value,
          converted: true,
          eventMetadata: metadata,
          platform: platform ?? 'unknown',
          appVersion: appVersion ?? 'unknown',
        }),
      },
      { token: req.headers.authorization?.replace('Bearer ', '') || '', requestId: req.id }
    );

    return {
      experimentId,
      userId,
      metricType,
      metricName,
      tracked: response.tracked,
      value,
      summary: response.tracked
        ? `Tracked ${metricType} metric "${metricName}" for experiment ${experimentId}`
        : `Event not tracked for experiment ${experimentId}`,
    };
  },
});
