import type { APIRoute } from 'astro';
import { logger, logApiRequest } from '../../utils/logger';
import { captureException } from '../../utils/sentry';

// ============================================================
// In-memory rate limiter (sliding window, per IP)
// ============================================================
interface RateLimitEntry {
  timestamps: number[];
}

const rateLimitStore = new Map<string, RateLimitEntry>();

const RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000; // 1 hour
const RATE_LIMIT_MAX_REQUESTS = 3; // max 3 newsletter signups per hour per IP

function checkRateLimit(ip: string): { allowed: boolean; remaining: number; resetAt: number } {
  const now = Date.now();
  const windowStart = now - RATE_LIMIT_WINDOW_MS;

  const entry = rateLimitStore.get(ip) ?? { timestamps: [] };
  entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);

  const remaining = RATE_LIMIT_MAX_REQUESTS - entry.timestamps.length;
  const resetAt = entry.timestamps.length > 0
    ? entry.timestamps[0] + RATE_LIMIT_WINDOW_MS
    : now + RATE_LIMIT_WINDOW_MS;

  if (entry.timestamps.length >= RATE_LIMIT_MAX_REQUESTS) {
    rateLimitStore.set(ip, entry);
    return { allowed: false, remaining: 0, resetAt };
  }

  entry.timestamps.push(now);
  rateLimitStore.set(ip, entry);
  return { allowed: true, remaining: remaining - 1, resetAt };
}

// ============================================================
// Input validation
// ============================================================
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

function validateEmail(email: string): string | null {
  if (!email || email.trim() === '') {
    return 'Email address is required.';
  }
  if (!EMAIL_REGEX.test(email.trim())) {
    return 'Please enter a valid email address.';
  }
  if (email.trim().length > 254) {
    return 'Email address is too long.';
  }
  return null;
}

// ============================================================
// Newsletter subscription handlers
// Supports: Mailchimp, ConvertKit, or simple SMTP notification
// ============================================================
async function subscribeToNewsletter(email: string): Promise<void> {
  const mailchimpApiKey = import.meta.env.MAILCHIMP_API_KEY;
  const mailchimpListId = import.meta.env.MAILCHIMP_LIST_ID;
  const mailchimpDataCenter = import.meta.env.MAILCHIMP_DC; // e.g. "us1"

  const convertkitApiKey = import.meta.env.CONVERTKIT_API_KEY;
  const convertkitFormId = import.meta.env.CONVERTKIT_FORM_ID;

  // Option 1: Mailchimp integration
  if (mailchimpApiKey && mailchimpListId && mailchimpDataCenter) {
    const url = `https://${mailchimpDataCenter}.api.mailchimp.com/3.0/lists/${mailchimpListId}/members`;
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Basic ${Buffer.from(`anystring:${mailchimpApiKey}`).toString('base64')}`,
      },
      body: JSON.stringify({
        email_address: email,
        status: 'pending', // Double opt-in
        tags: ['website-signup'],
      }),
    });

    if (!response.ok) {
      const error = await response.json() as { title?: string };
      // Handle already-subscribed gracefully
      if (error.title === 'Member Exists') {
        return;
      }
      throw new Error(`Mailchimp error: ${error.title}`);
    }
    return;
  }

  // Option 2: ConvertKit integration
  if (convertkitApiKey && convertkitFormId) {
    const url = `https://api.convertkit.com/v3/forms/${convertkitFormId}/subscribe`;
    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        api_key: convertkitApiKey,
        email,
      }),
    });

    if (!response.ok) {
      const error = await response.json() as { message?: string };
      throw new Error(`ConvertKit error: ${error.message}`);
    }
    return;
  }

  // Option 3: SMTP notification fallback
  const smtpHost = import.meta.env.SMTP_HOST;
  const smtpUser = import.meta.env.SMTP_USER;
  const smtpPass = import.meta.env.SMTP_PASS;
  const smtpPort = parseInt(import.meta.env.SMTP_PORT ?? '587', 10);
  const recipientEmail = import.meta.env.CONTACT_EMAIL ?? import.meta.env.SMTP_USER;

  if (smtpHost && smtpUser && smtpPass && recipientEmail) {
    try {
      const nodemailer = await import('nodemailer');
      const transporter = nodemailer.default.createTransport({
        host: smtpHost,
        port: smtpPort,
        secure: smtpPort === 465,
        auth: { user: smtpUser, pass: smtpPass },
      });

      await transporter.sendMail({
        from: `"WorkRoot Newsletter" <${smtpUser}>`,
        to: recipientEmail,
        subject: `[Newsletter] New subscriber: ${email}`,
        text: `New newsletter subscription\n\nEmail: ${email}\nSubscribed at: ${new Date().toISOString()}`,
      });
      return;
    } catch (err) {
      // If nodemailer isn't installed, fall through to console log path
      if (err instanceof Error && err.message.includes('Cannot find module')) {
        logger.warn('api.newsletter', 'nodemailer not available — subscriber logged only', { email });
        return;
      }
      await captureException(err, { scope: 'api.newsletter', extra: { provider: 'smtp' } });
      throw new Error('Failed to process subscription');
    }
  }

  // No integration configured — log and continue (dev/staging)
  logger.info('api.newsletter', 'No provider configured — subscriber logged only', { email });
}

// ============================================================
// CORS headers helper
// ============================================================
const ALLOWED_ORIGINS = ['https://workroot.in', 'https://www.workroot.in'];

function corsHeaders(requestOrigin?: string | null): HeadersInit {
  if (!import.meta.env.PROD) {
    return {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type',
    };
  }
  // Reflect the request origin if it is in the allowlist, otherwise default to primary domain
  const origin = requestOrigin && ALLOWED_ORIGINS.includes(requestOrigin)
    ? requestOrigin
    : 'https://workroot.in';
  return {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': origin,
    'Access-Control-Allow-Methods': 'POST, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type',
    'Vary': 'Origin',
  };
}

// ============================================================
// OPTIONS preflight handler
// ============================================================
export const OPTIONS: APIRoute = async ({ request }) => {
  return new Response(null, { status: 204, headers: corsHeaders(request.headers.get('origin')) });
};

// ============================================================
// POST handler
// ============================================================
export const POST: APIRoute = async ({ request, clientAddress }) => {
  const ip = clientAddress ?? 'unknown';
  const startTime = Date.now();
  const requestOrigin = request.headers.get('origin');

  // Rate limiting
  const rateLimit = checkRateLimit(ip);
  const rateLimitHeaders = {
    ...corsHeaders(requestOrigin),
    'X-RateLimit-Limit': String(RATE_LIMIT_MAX_REQUESTS),
    'X-RateLimit-Remaining': String(rateLimit.remaining),
    'X-RateLimit-Reset': String(Math.ceil(rateLimit.resetAt / 1000)),
  };

  if (!rateLimit.allowed) {
    logApiRequest({ scope: 'api.newsletter', method: 'POST', path: '/api/newsletter', status: 429, ip });
    return new Response(
      JSON.stringify({
        success: false,
        error: 'Too many requests. Please try again later.',
      }),
      { status: 429, headers: rateLimitHeaders }
    );
  }

  // Reject oversized payloads (max 4KB for email-only endpoint)
  const contentLength = parseInt(request.headers.get('content-length') ?? '0', 10);
  if (contentLength > 4096) {
    return new Response(
      JSON.stringify({ success: false, error: 'Request body too large.' }),
      { status: 413, headers: rateLimitHeaders }
    );
  }

  // Parse request body
  let email: string;
  try {
    const contentType = request.headers.get('content-type') ?? '';
    if (contentType.includes('application/json')) {
      const body = await request.json() as { email?: unknown };
      email = String(body.email ?? '').trim();
    } else {
      const formData = await request.formData();
      email = String(formData.get('email') ?? '').trim();
    }
  } catch {
    return new Response(
      JSON.stringify({ success: false, error: 'Invalid request body.' }),
      { status: 400, headers: rateLimitHeaders }
    );
  }

  // Validate email
  const validationError = validateEmail(email);
  if (validationError) {
    return new Response(
      JSON.stringify({ success: false, error: validationError }),
      { status: 422, headers: rateLimitHeaders }
    );
  }

  // Subscribe
  try {
    await subscribeToNewsletter(email.toLowerCase());
  } catch {
    logApiRequest({
      scope: 'api.newsletter',
      method: 'POST',
      path: '/api/newsletter',
      status: 500,
      ip,
      durationMs: Date.now() - startTime,
    });
    return new Response(
      JSON.stringify({
        success: false,
        error: 'Unable to process your subscription. Please try again.',
      }),
      { status: 500, headers: rateLimitHeaders }
    );
  }

  logApiRequest({
    scope: 'api.newsletter',
    method: 'POST',
    path: '/api/newsletter',
    status: 200,
    ip,
    durationMs: Date.now() - startTime,
  });
  return new Response(
    JSON.stringify({
      success: true,
      message: 'Thanks for subscribing! Check your inbox to confirm.',
    }),
    { status: 200, headers: rateLimitHeaders }
  );
};
