import { NextRequest, NextResponse } from 'next/server';
import { createServerClient } from '@supabase/ssr';
import { createClient as createAdminClient } from '@supabase/supabase-js';
import { z } from 'zod';

// ── Rate limiter ───────────────────────────────────────────────────────────
const signupAttempts = new Map<string, { count: number; resetAt: number }>();
const SIGNUP_LIMIT = 3;
const SIGNUP_WINDOW_MS = 60 * 60 * 1000; // 1 hour per IP

function getRealIp(req: NextRequest): string {
  return (
    req.headers.get('x-forwarded-for')?.split(',')[0].trim() ??
    req.headers.get('x-real-ip') ??
    'unknown'
  );
}

function isRateLimited(ip: string): boolean {
  const now = Date.now();
  const entry = signupAttempts.get(ip);
  if (!entry || now > entry.resetAt) {
    signupAttempts.set(ip, { count: 1, resetAt: now + SIGNUP_WINDOW_MS });
    return false;
  }
  if (entry.count >= SIGNUP_LIMIT) return true;
  entry.count += 1;
  return false;
}

// ── Validation schema ──────────────────────────────────────────────────────
const signupSchema = z.object({
  email: z.string().email('Invalid email address'),
  password: z
    .string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
    .regex(/[0-9]/, 'Password must contain at least one number')
    .regex(/[^A-Za-z0-9]/, 'Password must contain at least one special character'),
  fullName: z
    .string()
    .min(2, 'Full name must be at least 2 characters')
    .max(100, 'Full name too long'),
  // Signup key: a shared secret to prevent random people from signing up
  // Set ADMIN_SIGNUP_KEY in your .env — share it only with trusted people
  signupKey: z.string().min(1, 'Signup key is required'),
});

export async function POST(req: NextRequest) {
  const ip = getRealIp(req);

  // ── 1. Rate limit ─────────────────────────────────────────────────────────
  if (isRateLimited(ip)) {
    return NextResponse.json(
      { error: 'Too many signup attempts. Please try again later.' },
      { status: 429 }
    );
  }

  // ── 2. Parse & validate ───────────────────────────────────────────────────
  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return NextResponse.json({ error: 'Invalid request body.' }, { status: 400 });
  }

  const parsed = signupSchema.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: parsed.error.errors[0]?.message ?? 'Invalid data.' },
      { status: 422 }
    );
  }

  const { email, password, fullName, signupKey } = parsed.data;

  // ── 3. Validate signup key ────────────────────────────────────────────────
  const validSignupKey = process.env.ADMIN_SIGNUP_KEY;
  if (!validSignupKey) {
    // If no signup key is configured, disable signups entirely
    return NextResponse.json(
      { error: 'Admin signups are currently disabled.' },
      { status: 403 }
    );
  }

  // Constant-time comparison to prevent timing attacks
  if (signupKey !== validSignupKey) {
    return NextResponse.json(
      { error: 'Invalid signup key.' },
      { status: 403 }
    );
  }

  // ── 4. Create Supabase auth user using service role (admin client) ─────────
  // We use the service-role client so we can create users server-side
  // and immediately insert their profile.
  const supabaseAdmin = createAdminClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_ROLE_KEY!,
    {
      auth: {
        autoRefreshToken: false,
        persistSession: false,
      },
    }
  );

  const { data: authData, error: authError } = await supabaseAdmin.auth.admin.createUser({
    email,
    password,
    email_confirm: true, // auto-confirm so they can log in immediately
    user_metadata: {
      full_name: fullName,
    },
  });

  if (authError) {
    // Handle known Supabase error codes gracefully
    if (authError.message?.toLowerCase().includes('already registered') ||
        authError.message?.toLowerCase().includes('already been registered')) {
      return NextResponse.json(
        { error: 'An account with this email already exists.' },
        { status: 409 }
      );
    }
    console.error('Supabase auth signup error:', authError);
    return NextResponse.json(
      { error: 'Failed to create account. Please try again.' },
      { status: 500 }
    );
  }

  if (!authData.user) {
    return NextResponse.json(
      { error: 'Failed to create account.' },
      { status: 500 }
    );
  }

  // ── 5. Insert profile with role 'user' ────────────────────────────────────
  // Role defaults to 'user' — promote to 'admin' manually in the DB
  const { error: profileError } = await supabaseAdmin
    .from('profiles')
    .insert({
      id: authData.user.id,
      email: email.toLowerCase().trim(),
      full_name: fullName,
      role: 'user',
    });

  if (profileError) {
    // Profile insert failed — clean up the auth user to avoid orphaned accounts
    await supabaseAdmin.auth.admin.deleteUser(authData.user.id);
    console.error('Profile insert error:', profileError);
    return NextResponse.json(
      { error: 'Failed to create account profile. Please try again.' },
      { status: 500 }
    );
  }

  return NextResponse.json({
    success: true,
    message: 'Account created. Ask an admin to promote your role before logging in.',
  });
}