import { NextRequest, NextResponse } from 'next/server';

import { sendContributeNotification } from '@/services/contributeNotification';
import { saveUserMessage, UserMessageDto } from '@/services/userMessages';

type VerifyResponse = {
  success: boolean;
  'error-codes'?: string[];
  challenge_ts?: string;
  hostname?: string;
  action?: string;
  cdata?: string;
};

type SubmitUserMessagePayload = {
  dto: UserMessageDto;
  turnstileToken?: string;
};

async function verifyTurnstile(token: string, ip?: string) {
  const secret = process.env.TURNSTILE_SECRET_KEY;
  if (!secret) throw new Error('Missing TURNSTILE_SECRET_KEY');

  const formData = new FormData();
  formData.append('secret', secret);
  formData.append('response', token);
  if (ip) formData.append('remoteip', ip);

  const resp = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
    method: 'POST',
    body: formData,
  });

  const data = (await resp.json()) as VerifyResponse;
  return data;
}

export async function POST(request: NextRequest) {
  try {
    const body = (await request.json()) as SubmitUserMessagePayload;
    const dto = body?.dto;
    const token = typeof body?.turnstileToken === 'string' ? body.turnstileToken : '';

    if (!dto || !dto.email || !dto.message || dto.rowId === undefined || dto.rowId === null) {
      return NextResponse.json({ success: false, message: 'Missing message data' }, { status: 400 });
    }

    if (!token) {
      return NextResponse.json(
        { success: false, message: 'Missing Turnstile token.' },
        { status: 400 }
      );
    }

    const forwarded = request.headers.get('x-forwarded-for');
    const ip =
      request.headers.get('cf-connecting-ip') ??
      (forwarded ? forwarded.split(',')[0]?.trim() : undefined);

    const verify = await verifyTurnstile(token, ip);

    if (!verify.success) {
      return NextResponse.json(
        {
          success: false,
          message: 'Turnstile verification failed.',
          codes: verify['error-codes'] ?? [],
        },
        { status: 403 }
      );
    }

    const saved = await saveUserMessage(dto);

    // Always notify (best-effort), independent of the DB write: the email carries
    // the full submission + save status, so nothing is lost if persistence fails.
    const notified = await sendContributeNotification(dto, saved);

    // Treat the submission as received if it was persisted OR the email backstop
    // caught it — only a total failure of both is a user-facing error.
    if (saved || notified) {
      return NextResponse.json(
        { success: true, message: 'Message submitted successfully.', saved, notified },
        { status: 200 }
      );
    }

    return NextResponse.json(
      { success: false, message: 'Failed to submit message.' },
      { status: 500 }
    );
  } catch (error) {
    console.error('Error submitting user message:', error);
    return NextResponse.json(
      { success: false, message: 'Failed to submit message.' },
      { status: 500 }
    );
  }
}
