import { z } from 'zod';
import { BasePack } from '../base-pack.js';
import type { TwilioClient } from '../../client.js';
import { toE164, isValidPhone } from '../../utils/validators.js';

export class VerifyPack extends BasePack {
  readonly name = 'verify';
  readonly description = 'OTP, 2FA, and identity verification tools';
  readonly keywords = ['otp', 'verify', '2fa', 'mfa', 'auth', 'verification', 'code', 'sms', 'pin'];

  constructor(client: TwilioClient) {
    super(client);
  }

  setup(): void {
    // ─── twilio_otp_send ───
    this.registerTool({
      name: 'twilio_otp_send',
      description: 'Send a one-time password (OTP) verification code via SMS, WhatsApp, email, or voice call.',
      category: 'verify',
      safety: 'yellow',
      tier: 2,
      annotations: { costHint: true, estimatedCost: '~$0.05 per verification' },
      inputSchema: z.object({
        to: z.string().describe('Phone number or email to send verification to'),
        channel: z.enum(['sms', 'whatsapp', 'email', 'voice']).describe('Delivery channel for the code'),
        service_name: z.string().optional().describe('Friendly name for the verify service (auto-created if needed)'),
        code_length: z.number().min(4).max(10).optional().describe('Length of verification code (4-10 digits, default 6)'),
      }),
      _meta: {
        labels: {
          category: "verification",
          access: "write",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Validate phone number if not email
          let to = params.to;
          if (params.channel !== 'email') {
            to = toE164(params.to);
            if (!isValidPhone(to)) {
              return this.errorResult(`Invalid phone number: ${params.to}`);
            }
          }

          // Find or create a verify service
          const serviceName = params.service_name || 'Default Verify Service';
          let service;
          
          try {
            // Try to find existing service
            const services = await this.client.execute(c =>
              c.verify.v2.services.list({ limit: 50 })
            );
            service = services.find(s => s.friendlyName === serviceName);
            
            if (!service) {
              // Create new service
              service = await this.client.execute(c =>
                c.verify.v2.services.create({
                  friendlyName: serviceName,
                  codeLength: params.code_length || 6,
                })
              );
            }
          } catch (err: any) {
            return this.errorResult(`Failed to access verify service: ${err.message}`);
          }

          // Send verification
          const verification = await this.client.execute(c =>
            c.verify.v2
              .services(service.sid)
              .verifications.create({
                to: to,
                channel: params.channel,
              })
          );

          return this.textResult(
            `Verification code sent!\n` +
            `  Verification SID: ${verification.sid}\n` +
            `  To: ${verification.to}\n` +
            `  Channel: ${verification.channel}\n` +
            `  Status: ${verification.status}\n` +
            `  Service: ${serviceName} (${service.sid})\n\n` +
            `Use twilio_otp_check to verify the code.`
          );
        } catch (err: any) {
          return this.errorResult(`Failed to send verification: ${err.message}`);
        }
      },
    });

    // ─── twilio_otp_check ───
    this.registerTool({
      name: 'twilio_otp_check',
      description: 'Verify a one-time password (OTP) code. Returns whether the code is valid.',
      category: 'verify',
      safety: 'yellow',
      tier: 2,
      annotations: { readOnlyHint: false },
      inputSchema: z.object({
        to: z.string().describe('Phone number or email that received the code'),
        code: z.string().describe('Verification code to check'),
      }),
      _meta: {
        labels: {
          category: "verification",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Validate phone number if not email
          let to = params.to;
          if (!params.to.includes('@')) {
            to = toE164(params.to);
            if (!isValidPhone(to)) {
              return this.errorResult(`Invalid phone number: ${params.to}`);
            }
          }

          // Find the verify service (use first available)
          const services = await this.client.execute(c =>
            c.verify.v2.services.list({ limit: 1 })
          );

          if (services.length === 0) {
            return this.errorResult('No verify service found. Send a verification first with twilio_otp_send.');
          }

          const service = services[0];

          // Check the verification
          const verificationCheck = await this.client.execute(c =>
            c.verify.v2
              .services(service.sid)
              .verificationChecks.create({
                to: to,
                code: params.code,
              })
          );

          const isValid = verificationCheck.status === 'approved';

          return this.jsonResult(
            {
              valid: isValid,
              status: verificationCheck.status,
              to: verificationCheck.to,
              channel: verificationCheck.channel,
              sid: verificationCheck.sid,
            },
            `Verification Check:\n` +
            `  Valid: ${isValid ? '✓ YES' : '✗ NO'}\n` +
            `  Status: ${verificationCheck.status}\n` +
            `  To: ${verificationCheck.to}\n` +
            `  Channel: ${verificationCheck.channel || 'N/A'}`
          );
        } catch (err: any) {
          return this.errorResult(`Verification check failed: ${err.message}`);
        }
      },
    });

    // ─── twilio_auth_flow_setup ───
    this.registerTool({
      name: 'twilio_auth_flow_setup',
      description: 'Create and configure a complete authentication flow with custom settings (channels, code length, TTL, rate limits).',
      category: 'verify',
      safety: 'yellow',
      tier: 2,
      annotations: { destructiveHint: false },
      inputSchema: z.object({
        name: z.string().describe('Friendly name for this auth flow'),
        channels: z.array(z.enum(['sms', 'voice', 'whatsapp', 'email'])).describe('Allowed verification channels'),
        code_length: z.number().min(4).max(10).optional().describe('Length of verification code (default 6)'),
        ttl: z.number().optional().describe('Time-to-live in seconds for verification codes (default 300)'),
        rate_limit_per_minute: z.number().optional().describe('Maximum verification attempts per minute (default 5)'),
      }),
      _meta: {
        labels: {
          category: "verification",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Create the verify service with custom configuration
          const service = await this.client.execute(c =>
            c.verify.v2.services.create({
              friendlyName: params.name,
              codeLength: params.code_length || 6,
              lookupEnabled: true,
              skipSmsToLandlines: true,
              dtmfInputRequired: false,
            })
          );

          // Update rate limits if specified
          if (params.rate_limit_per_minute) {
            await this.client.execute(c =>
              c.verify.v2.services(service.sid).rateLimits.create({
                uniqueName: 'default-rate-limit',
                description: 'Default rate limit for auth flow',
              })
            );
          }

          // Configure messaging (may not be available on all accounts)
          await this.client.execute(c =>
            c.verify.v2.services(service.sid).messagingConfigurations.create({
              country: 'US',
              messagingServiceSid: 'default',
            })
          ).catch(() => null);

          const summary = {
            service_sid: service.sid,
            name: params.name,
            code_length: params.code_length || 6,
            ttl: params.ttl || 300,
            channels: params.channels,
            rate_limit: params.rate_limit_per_minute || 5,
            status: 'active',
          };

          return this.jsonResult(
            summary,
            `Authentication Flow Created!\n` +
            `  Service SID: ${service.sid}\n` +
            `  Name: ${params.name}\n` +
            `  Code Length: ${params.code_length || 6} digits\n` +
            `  TTL: ${params.ttl || 300} seconds\n` +
            `  Channels: ${params.channels.join(', ')}\n` +
            `  Rate Limit: ${params.rate_limit_per_minute || 5} attempts/minute\n\n` +
            `Use this service with twilio_otp_send by specifying service_name="${params.name}"`
          );
        } catch (err: any) {
          return this.errorResult(`Failed to create auth flow: ${err.message}`);
        }
      },
    });

    // ─── twilio_silent_network_auth ───
    this.registerTool({
      name: 'twilio_silent_network_auth',
      description: 'Attempt Silent Network Authentication (SNA) for passwordless verification. Falls back to SMS/voice if SNA is unavailable.',
      category: 'verify',
      safety: 'yellow',
      tier: 2,
      annotations: { costHint: true, estimatedCost: '~$0.03 per attempt (SNA), ~$0.05 (SMS fallback)' },
      inputSchema: z.object({
        phone_number: z.string().describe('Phone number to verify via SNA'),
        fallback_channel: z.enum(['sms', 'voice']).optional().describe('Fallback channel if SNA unavailable (default: sms)'),
      }),
      _meta: {
        labels: {
          category: "verification",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        const phone = toE164(params.phone_number);
        if (!isValidPhone(phone)) {
          return this.errorResult(`Invalid phone number: ${params.phone_number}`);
        }

        try {
          // Find or create verify service
          let service;
          const services = await this.client.execute(c =>
            c.verify.v2.services.list({ limit: 1 })
          );

          if (services.length === 0) {
            service = await this.client.execute(c =>
              c.verify.v2.services.create({
                friendlyName: 'SNA Verify Service',
                codeLength: 6,
              })
            );
          } else {
            service = services[0];
          }

          // Attempt SNA verification
          let verification;
          let methodUsed = 'sna';
          
          try {
            verification = await this.client.execute(c =>
              c.verify.v2
                .services(service.sid)
                .verifications.create({
                  to: phone,
                  channel: 'sna',
                })
            );
          } catch (snaErr: any) {
            // SNA failed, fall back to SMS/voice
            methodUsed = params.fallback_channel || 'sms';
            verification = await this.client.execute(c =>
              c.verify.v2
                .services(service.sid)
                .verifications.create({
                  to: phone,
                  channel: methodUsed,
                })
            );
          }

          const isSilent = methodUsed === 'sna';

          return this.jsonResult(
            {
              verification_sid: verification.sid,
              phone_number: phone,
              method_used: methodUsed,
              silent_auth: isSilent,
              status: verification.status,
              requires_code_check: !isSilent,
            },
            `${isSilent ? '🔐 Silent Network Auth' : '📱 Fallback Verification'} Initiated\n` +
            `  Verification SID: ${verification.sid}\n` +
            `  Phone: ${phone}\n` +
            `  Method: ${methodUsed.toUpperCase()}${isSilent ? ' (passwordless)' : ''}\n` +
            `  Status: ${verification.status}\n\n` +
            (isSilent 
              ? 'No code needed — verification completed via network authentication.' 
              : `Verification code sent via ${methodUsed.toUpperCase()}. Use twilio_otp_check to verify the code.`)
          );
        } catch (err: any) {
          return this.errorResult(`Silent network auth failed: ${err.message}`);
        }
      },
    });
  }
}
