import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import {
  telemetryListPolicies,
  telemetryPreviewPolicy,
  telemetryCreatePolicy,
  telemetryUpdatePolicy,
  telemetryDeletePolicy,
  telemetryUpdateCluster,
} from '../../lib/platform-client.js';
import type { McpToolRequest } from '../tools/types.js';

const tokenOf = (req: McpToolRequest) => req.headers.authorization?.slice(7);

// ── Shared targeting sub-schema ────────────────────────────────────────────
const TargetingSchema = z
  .object({
    userIds: z.array(z.string()).optional(),
    platforms: z.array(z.string()).optional().describe('e.g. ios, android, web'),
    channels: z.array(z.string()).optional().describe('e.g. release, beta, internal'),
    osFamilies: z.array(z.string()).optional(),
    appVersions: z.array(z.string()).optional(),
    releaseChannels: z.array(z.string()).optional(),
    countryCodes: z.array(z.string()).optional(),
    percentage: z.coerce.number().min(0).max(100).optional().describe('% of installs to target'),
  })
  .optional()
  .describe('Targeting criteria — omit to apply to all installs');

// ── platform.telemetry.policies.list ──────────────────────────────────────

registerTool({
  name: 'platform.telemetry.policies.list',
  description: 'List all telemetry collection policies for a product. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID to scope the query'),
  }),
  async execute(args, req) {
    return telemetryListPolicies({
      token: tokenOf(req),
      requestId: req.id,
      productId: args.productId,
    });
  },
});

// ── platform.telemetry.policies.preview ──────────────────────────────────

registerTool({
  name: 'platform.telemetry.policies.preview',
  description:
    'Preview how many clients a targeting config would match (dry-run before creating a policy). Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID to scope the preview'),
    targeting: TargetingSchema,
  }),
  async execute(args, req) {
    return telemetryPreviewPolicy(
      { targeting: args.targeting as Record<string, unknown> | undefined },
      { token: tokenOf(req), requestId: req.id, productId: args.productId }
    );
  },
});

// ── platform.telemetry.policies.create ───────────────────────────────────

registerTool({
  name: 'platform.telemetry.policies.create',
  description: [
    'Create a telemetry collection policy. expiresAt is REQUIRED — never create an open-ended policy.',
    'eventTypes defaults to [warn, error, fatal]. samplingRate 0.0–1.0 (1.0 = 100%). Requires admin role.',
  ].join(' '),
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID'),
    name: z.string().min(1).max(200).describe('Human-readable policy name'),
    description: z.string().optional(),
    expiresAt: z
      .string()
      .datetime()
      .describe('ISO 8601 expiry — REQUIRED. Policies must not run indefinitely.'),
    eventTypes: z
      .array(z.enum(['debug', 'info', 'warn', 'error', 'fatal']))
      .optional()
      .describe('Event types to collect (default: warn, error, fatal)'),
    modules: z.array(z.string()).optional().describe('Module names to target (empty = all)'),
    samplingRate: z.coerce
      .number()
      .min(0)
      .max(1)
      .optional()
      .describe('Fraction of events to collect (default: 1.0)'),
    enabled: z.boolean().optional().describe('Enable immediately (default: true)'),
    priority: z.coerce.number().min(0).max(999).optional(),
    startsAt: z.string().datetime().optional(),
    targeting: TargetingSchema,
  }),
  async execute(args, req) {
    const { productId, ...body } = args;
    return telemetryCreatePolicy(body as Record<string, unknown>, {
      token: tokenOf(req),
      requestId: req.id,
      productId,
    });
  },
});

// ── platform.telemetry.policies.update ──────────────────────────────────

registerTool({
  name: 'platform.telemetry.policies.update',
  description: 'Update an existing telemetry policy. All fields are optional. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID (for x-product-id scoping)'),
    policyId: z.string().min(1).describe('Policy ID to update'),
    name: z.string().min(1).max(200).optional(),
    description: z.string().optional(),
    enabled: z.boolean().optional(),
    expiresAt: z.string().datetime().optional().describe('Update or extend expiry (ISO 8601)'),
    eventTypes: z.array(z.enum(['debug', 'info', 'warn', 'error', 'fatal'])).optional(),
    modules: z.array(z.string()).optional(),
    samplingRate: z.coerce.number().min(0).max(1).optional(),
    targeting: TargetingSchema,
  }),
  async execute(args, req) {
    const { productId, policyId, ...body } = args;
    return telemetryUpdatePolicy(policyId, body as Record<string, unknown>, {
      token: tokenOf(req),
      requestId: req.id,
      productId,
    });
  },
});

// ── platform.telemetry.policies.delete ──────────────────────────────────

registerTool({
  name: 'platform.telemetry.policies.delete',
  description: 'Delete a telemetry policy by ID. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID (for x-product-id scoping)'),
    policyId: z.string().min(1).describe('Policy ID to delete'),
  }),
  async execute(args, req) {
    return telemetryDeletePolicy(args.policyId, {
      token: tokenOf(req),
      requestId: req.id,
      productId: args.productId,
    });
  },
});

// ── platform.telemetry.clusters.updateStatus ────────────────────────────

registerTool({
  name: 'platform.telemetry.clusters.updateStatus',
  description:
    'Resolve or ignore an error cluster (fingerprinted error group). Use resolved when fixed, ignored to suppress. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    productId: z.string().min(1).describe('Product ID (for x-product-id scoping)'),
    clusterId: z.string().min(1).describe('Cluster ID (fingerprint:yyyyMM)'),
    pk: z
      .string()
      .min(1)
      .describe('Cluster partition key (productId:platform:module — from clusters list result)'),
    status: z.enum(['open', 'resolved', 'ignored']).describe('New cluster status'),
  }),
  async execute(args, req) {
    return telemetryUpdateCluster(args.clusterId, args.pk, args.status, {
      token: tokenOf(req),
      requestId: req.id,
      productId: args.productId,
    });
  },
});
