import { NextRequest, NextResponse } from 'next/server';
import { getPrisma } from '@/lib/db';
import crypto from 'crypto';

function safeCompare(a: string, b: string): boolean {
  const bufA = Buffer.from(a);
  const bufB = Buffer.from(b);
  if (bufA.length !== bufB.length) {
    crypto.timingSafeEqual(bufA, bufA);
    return false;
  }
  return crypto.timingSafeEqual(bufA, bufB);
}

export async function POST(req: NextRequest) {
  try {
    const signature = req.headers.get('x-n8n-signature') || '';
    const expectedSecret = process.env.N8N_WEBHOOK_SECRET || '';

    if (!expectedSecret || !signature || !safeCompare(signature, expectedSecret)) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'UNAUTHORIZED',
          metadata: {}
        }
      }, { status: 401 });
    }

    const body = await req.json();
    const { idempotencyKey, uploaderId, sales, status, errorMessage } = body;

    if (!idempotencyKey || !uploaderId) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'BAD_REQUEST',
          metadata: { message: 'idempotencyKey and uploaderId are required.' }
        }
      }, { status: 400 });
    }

    const prisma = getPrisma();

    // Support n8n failure reporting
    if (status === 'FAILED') {
      await prisma.salesImportJob.upsert({
        where: { idempotencyKey },
        create: {
          idempotencyKey,
          status: 'FAILED',
          errorMessage: errorMessage || 'n8n background processing failed',
          uploadedBy: uploaderId
        },
        update: {
          status: 'FAILED',
          errorMessage: errorMessage || 'n8n background processing failed'
        }
      });
      return NextResponse.json({
        success: true,
        code: 'IMPORT_FAILED_REPORTED',
        metadata: { idempotencyKey }
      }, { status: 200 });
    }

    if (!Array.isArray(sales)) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'BAD_REQUEST',
          metadata: { message: 'sales must be an array.' }
        }
      }, { status: 400 });
    }

    let result;
    try {
      result = await prisma.$transaction(async (tx: any) => {
        // Elevate privileges to admin role to bypass RLS for n8n batch operations
        await tx.$executeRawUnsafe(`SET LOCAL app.current_user_role = 'admin';`);

        // 1. Check idempotency
        const existing = await tx.salesResult.findMany({
          where: {
            idempotencyKey: {
              startsWith: `${idempotencyKey}-`
            }
          }
        });

        if (existing.length > 0) {
          return {
            alreadyProcessed: true,
            count: existing.length
          };
        }

        // 2. Resolve usernames and hotel codes
        const uniqueUsernames = Array.from(new Set(sales.map(s => s.username).filter(Boolean))) as string[];
        const uniqueHotelCodes = Array.from(new Set(sales.map(s => s.hotelCode).filter(Boolean))) as string[];

        const dbUsers = await tx.user.findMany({
          where: { username: { in: uniqueUsernames } }
        });

        const dbHotels = await tx.hotel.findMany({
          where: { code: { in: uniqueHotelCodes } }
        });

        const userMap = new Map<string, any>(dbUsers.map((u: any) => [u.username, u]));
        const hotelMap = new Map<string, any>(dbHotels.map((h: any) => [h.code, h]));

        // 3. Save records
        const createdSales = [];
        for (let i = 0; i < sales.length; i++) {
          const s = sales[i];
          const user = userMap.get(s.username);
          const hotel = hotelMap.get(s.hotelCode);

          if (!user || !hotel) {
            throw new Error(`User or Hotel not found for record: ${JSON.stringify(s)}`);
          }

          const created = await tx.salesResult.create({
            data: {
              source: 'API',
              hotelId: hotel.id,
              userId: user.id,
              period: s.period,
              amount: Number(s.amount),
              salesCount: Number(s.salesCount),
              idempotencyKey: `${idempotencyKey}-${i}`,
              transactionId: s.transactionId || null,
              uploadedBy: uploaderId,
              status: 'PENDING',
              isAnomaly: s.isAnomaly || false,
              flaggedReason: s.flaggedReason || null
            }
          });
          createdSales.push(created);
        }

        // 4. Create Audit Log
        await tx.auditLog.create({
          data: {
            userId: uploaderId,
            action: 'CREATE',
            targetTable: 'sales_results',
            targetId: createdSales[0]?.id || 0,
            newValue: {
              count: createdSales.length,
              idempotencyKey
            }
          }
        });

        // Update import job to SUCCESS
        await tx.salesImportJob.upsert({
          where: { idempotencyKey },
          create: {
            idempotencyKey,
            status: 'SUCCESS',
            uploadedBy: uploaderId
          },
          update: {
            status: 'SUCCESS'
          }
        });

        return {
          alreadyProcessed: false,
          count: createdSales.length
        };
      });
    } catch (txErr: any) {
      try {
        await prisma.salesImportJob.upsert({
          where: { idempotencyKey },
          create: {
            idempotencyKey,
            status: 'FAILED',
            errorMessage: txErr.message,
            uploadedBy: uploaderId
          },
          update: {
            status: 'FAILED',
            errorMessage: txErr.message
          }
        });
      } catch (upsertErr) {
        console.error('Failed to upsert failed status:', upsertErr);
      }
      throw txErr;
    }

    return NextResponse.json({
      success: true,
      code: result.alreadyProcessed ? 'IMPORT_ALREADY_PROCESSED' : 'IMPORT_SUCCESSFUL',
      metadata: {
        count: result.count,
        idempotencyKey
      }
    }, { status: 201 });

  } catch (err: any) {
    console.error('Batch save error:', err);
    return NextResponse.json({
      success: false,
      error: {
        code: 'BATCH_SAVE_FAILED',
        metadata: { message: err.message }
      }
    }, { status: 500 });
  }
}
