import { getSupabaseAdmin, createClient } from '@/lib/supabase/server';
import { NextRequest, NextResponse } from 'next/server';
import { logger } from '@/lib/logger';
import { checkRateLimit, getClientIP, createRateLimitResponse } from '@/lib/rate-limit';
import { createCheckoutSession } from '@/lib/stripe/server';
import { withCSRFProtection } from '@/lib/csrf';
import { 
  PAYMENT_AMOUNT, 
  RATE_LIMIT_REQUESTS_PER_USER as PAYMENT_RATE_LIMIT,
  RATE_LIMIT_WINDOW_MS as PAYMENT_WINDOW_MS,
  HTTP_STATUS_INTERNAL_SERVER_ERROR 
} from '@/lib/constants';

const handler = async (request: NextRequest) => {
  try {
    // --- Rate limiting (by IP as initial check) ---
    const clientIP = getClientIP(request);
    const ipRateLimit = await checkRateLimit(`payment-ip:${clientIP}`, PAYMENT_RATE_LIMIT, PAYMENT_WINDOW_MS);
    
    if (!ipRateLimit.allowed) {
      const retryAfter = Math.ceil((ipRateLimit.resetTime - Date.now()) / 1000);
      return createRateLimitResponse(clientIP, retryAfter);
    }
    
    const supabase = await createClient();
    const {
      data: { user },
    } = await supabase.auth.getUser();
    
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }
    
    // --- Stricter rate limiting by user ID ---
    const userRateLimit = await checkRateLimit(`payment-user:${user.id}`, PAYMENT_RATE_LIMIT, PAYMENT_WINDOW_MS);
    
    if (!userRateLimit.allowed) {
      const retryAfter = Math.ceil((userRateLimit.resetTime - Date.now()) / 1000);
      return createRateLimitResponse(user.id, retryAfter);
    }

    const body = await request.json();
    const { match_id: matchId, company_id: companyId } = body;
    const amount = PAYMENT_AMOUNT; // Hardcoded amount to prevent client override

    if (!matchId || !companyId) {
      return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
    }

    // Verify user owns the company
    const { data: company } = await supabase
      .from('companies')
      .select('id, name')
      .eq('id', companyId)
      .eq('profile_id', user.id)
      .single();

    if (!company) {
      return NextResponse.json({ error: 'Company not found or unauthorized' }, { status: 403 });
    }

    // Verify match exists and belongs to company's job (can be in any status except rejected)
    const { data: match } = await supabase
      .from('matches')
      .select('status, jobs!inner(company_id, title)')
      .eq('id', matchId)
      .neq('status', 'rejected')
      .eq('jobs.company_id', companyId)
      .single();

    if (!match) {
      return NextResponse.json({ error: 'Match not found, already rejected, or unauthorized' }, { status: 403 });
    }

    // Check if match is already hired (prevent duplicate hires)
    if (match.status === 'hired') {
      return NextResponse.json({ error: 'This worker has already been hired for this job' }, { status: 400 });
    }

    // Check if payment already exists and is charged (prevent duplicate charges)
    const { data: existingPayment } = await supabase
      .from('payments')
      .select('id, status')
      .eq('match_id', matchId)
      .in('status', ['charged', 'pending'])
      .maybeSingle();

    if (existingPayment?.status === 'charged') {
      return NextResponse.json({ error: 'Payment already completed for this hire' }, { status: 400 });
    }

    // Build success/cancel URLs
    const origin = request.headers.get('origin') || process.env.NEXT_PUBLIC_APP_URL || 'https://rivet.rateright.com.au';
    const jobTitle = (match.jobs as { title?: string }).title || 'Job';

    // Create Stripe Checkout Session with contractor's email for receipt
    const { url: checkoutUrl } = await createCheckoutSession({
      amount,
      matchId,
      companyId,
      companyName: company.name,
      description: `Hire for ${jobTitle}`,
      successUrl: `${origin}/contractor/payment-success?match_id=${matchId}&session_id={CHECKOUT_SESSION_ID}`,
      cancelUrl: `${origin}/contractor/matches`,
      customerEmail: user.email || undefined,
    });

    if (!checkoutUrl) {
      return NextResponse.json({ error: 'Failed to create checkout session' }, { status: HTTP_STATUS_INTERNAL_SERVER_ERROR });
    }

    // Pre-create payment record via admin client
    // NOTE: DB trigger requires match status='hired' before payment insert.
    // Temporarily set match to 'hired' to satisfy trigger, then revert.
    const supabaseService = getSupabaseAdmin();

    // Step 1: Temporarily mark match as hired to pass DB trigger
    const { error: matchUpdateError } = await supabaseService
      .from('matches')
      .update({ 
        status: 'hired',
        contractor_action: 'accepted',
      })
      .eq('id', matchId);

    if (matchUpdateError) {
      logger.error('Failed to mark match as hired temporarily:', matchUpdateError);
      return NextResponse.json({ error: 'Failed to initiate payment process' }, { status: HTTP_STATUS_INTERNAL_SERVER_ERROR });
    }

    // Step 2: Insert payment record
    const { error: paymentInsertError } = await supabaseService
      .from('payments')
      .upsert(
        {
          match_id: matchId,
          company_id: companyId,
          amount,
          status: 'pending',
          stripe_payment_id: `checkout_${matchId}`,
        },
        { onConflict: 'match_id', ignoreDuplicates: false }
      );

    if (paymentInsertError) {
      logger.error('Failed to insert payment record:', paymentInsertError);
      // Attempt to revert match status
      await supabaseService
        .from('matches')
        .update({ status: 'accepted' })
        .eq('id', matchId);
      return NextResponse.json({ error: 'Failed to create payment record' }, { status: HTTP_STATUS_INTERNAL_SERVER_ERROR });
    }

    // Step 3: Revert match to 'accepted' (payment pending)
    const { error: revertError } = await supabaseService
      .from('matches')
      .update({ 
        status: 'accepted',
        contractor_action: 'accepted',
        hired_at: null,
        fee_charged: false,
      })
      .eq('id', matchId);

    if (revertError) {
      logger.error('Failed to revert match to accepted:', revertError);
      // We don't abort here because the payment record exists and Stripe session is created,
      // but it's a data anomaly to log.
    }

    return NextResponse.json({ url: checkoutUrl });
  } catch (error) {
    logger.error('Payment creation error:', error);
    if (error instanceof Error && error.message.includes('Stripe')) {
      return NextResponse.json({ error: 'Payment service unavailable' }, { status: 503 });
    }
    return NextResponse.json({ error: 'Internal server error' }, { status: HTTP_STATUS_INTERNAL_SERVER_ERROR });
  }
}

// Apply CSRF protection to the handler
export const POST = withCSRFProtection(handler);
