import { NextRequest, NextResponse } from 'next/server';
import { withAuth } from '@/lib/api-guards';
import * as XLSX from 'xlsx';

export const POST = withAuth(async (req, { session, prisma }) => {
  try {
    const idempotencyKey = req.headers.get('idempotency-key');
    if (!idempotencyKey) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'MISSING_IDEMPOTENCY_KEY',
          metadata: {}
        }
      }, { status: 400 });
    }

    // 1. Check idempotency / job status
    const existingJob = await prisma.salesImportJob.findUnique({
      where: { idempotencyKey }
    });

    if (existingJob) {
      if (existingJob.status === 'SUCCESS') {
        const existingSales = await prisma.salesResult.findMany({
          where: {
            idempotencyKey: {
              startsWith: `${idempotencyKey}-`
            }
          }
        });
        const totalAmount = existingSales.reduce((acc: number, cur: any) => acc + Number(cur.amount), 0);
        return NextResponse.json({
          success: true,
          code: 'IMPORT_ALREADY_PROCESSED',
          metadata: {
            count: existingSales.length,
            totalAmount,
            idempotencyKey
          }
        });
      }

      if (existingJob.status === 'PROCESSING') {
        return NextResponse.json({
          success: true,
          code: 'IMPORT_ACCEPTED',
          metadata: {
            idempotencyKey,
            status: 'PROCESSING'
          }
        }, { status: 202 });
      }

      // If FAILED, allow retrying by deleting the old failed job
      if (existingJob.status === 'FAILED') {
        await prisma.salesImportJob.delete({
          where: { idempotencyKey }
        });
      }
    }

    // 2. Parse file
    const formData = await req.formData();
    const file = formData.get('file') as File;
    if (!file) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'FILE_REQUIRED',
          metadata: {}
        }
      }, { status: 400 });
    }

    const buffer = Buffer.from(await file.arrayBuffer());
    const workbook = XLSX.read(buffer, { type: 'buffer' });
    const sheetName = workbook.SheetNames[0];
    const sheet = workbook.Sheets[sheetName];
    const rawRows = XLSX.utils.sheet_to_json(sheet) as any[];

    if (!rawRows || rawRows.length === 0) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'EMPTY_FILE',
          metadata: {}
        }
      }, { status: 400 });
    }

    // 3. Collect rows and validate
    const rows: {
      username: string;
      period: string;
      hotelCode: string;
      amount: number;
      salesCount: number;
      transactionId?: string;
      rowIndex: number;
    }[] = [];

    const errors: {
      row: number;
      column: string;
      value: any;
      code: string;
      metadata: any;
    }[] = [];

    for (let i = 0; i < rawRows.length; i++) {
      const row = rawRows[i];
      const rowIndex = i + 2;

      const username = String(row['Colaborador'] || '').trim();
      const period = String(row['Periodo'] || '').trim();
      const hotelCode = String(row['Hotel'] || '').trim();
      const amountVal = row['Monto'];
      const salesCountVal = row['Cantidad'];
      const transactionId = row['Id_Transaccion'] ? String(row['Id_Transaccion']).trim() : undefined;

      const amount = typeof amountVal === 'number' ? amountVal : parseFloat(String(amountVal || ''));
      const salesCount = typeof salesCountVal === 'number' ? salesCountVal : parseInt(String(salesCountVal || ''));

      rows.push({
        username,
        period,
        hotelCode,
        amount,
        salesCount,
        transactionId,
        rowIndex
      });

      // Basic validations
      if (!username) {
        errors.push({
          row: rowIndex,
          column: 'Colaborador',
          value: '',
          code: 'USER_REQUIRED',
          metadata: {}
        });
      }

      if (!period || !/^\d{4}-\d{2}$/.test(period)) {
        errors.push({
          row: rowIndex,
          column: 'Periodo',
          value: period,
          code: 'INVALID_PERIOD_FORMAT',
          metadata: { expected: 'YYYY-MM' }
        });
      }

      if (!hotelCode) {
        errors.push({
          row: rowIndex,
          column: 'Hotel',
          value: '',
          code: 'HOTEL_REQUIRED',
          metadata: {}
        });
      }

      if (isNaN(amount) || amount <= 0) {
        errors.push({
          row: rowIndex,
          column: 'Monto',
          value: amountVal,
          code: 'INVALID_AMOUNT',
          metadata: { value: amountVal }
        });
      }

      if (isNaN(salesCount) || salesCount <= 0) {
        errors.push({
          row: rowIndex,
          column: 'Cantidad',
          value: salesCountVal,
          code: 'INVALID_COUNT',
          metadata: { value: salesCountVal }
        });
      }
    }

    // Resolve entities and check exists/RBAC
    const uniqueUsernames = Array.from(new Set(rows.map(r => r.username).filter(Boolean)));
    const uniqueHotelCodes = Array.from(new Set(rows.map(r => r.hotelCode).filter(Boolean)));

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

    const dbHotels = await prisma.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]));

    // Find active user for region verification
    const activeUser = await prisma.user.findUnique({
      where: { id: session.userId },
      include: { hotel: true }
    });
    const activeRegionId = activeUser?.hotel?.regionId;

    for (const r of rows) {
      if (r.username && !userMap.has(r.username)) {
        errors.push({
          row: r.rowIndex,
          column: 'Colaborador',
          value: r.username,
          code: 'USER_NOT_FOUND',
          metadata: { username: r.username }
        });
      }

      const hotel = hotelMap.get(r.hotelCode);
      if (r.hotelCode && !hotel) {
        errors.push({
          row: r.rowIndex,
          column: 'Hotel',
          value: r.hotelCode,
          code: 'HOTEL_NOT_FOUND',
          metadata: { hotelCode: r.hotelCode }
        });
      }

      // Enforce Leader region isolation
      if (session.role === 'commercial_leader' && hotel && hotel.regionId !== activeRegionId) {
        errors.push({
          row: r.rowIndex,
          column: 'Hotel',
          value: r.hotelCode,
          code: 'HOTEL_REGION_MISMATCH',
          metadata: { hotelCode: r.hotelCode, regionId: activeRegionId }
        });
      }
    }

    if (errors.length > 0) {
      return NextResponse.json({
        success: false,
        error: {
          code: 'IMPORT_VALIDATION_FAILED',
          details: errors
        }
      }, { status: 400 });
    }

    // Create the SalesImportJob record first
    await prisma.salesImportJob.create({
      data: {
        idempotencyKey,
        status: 'PROCESSING',
        uploadedBy: session.userId
      }
    });

    // 5. Dispatch to n8n or direct save
    const useN8n = process.env.N8N_WEBHOOK_URL && process.env.NODE_ENV !== 'test' && process.env.IS_E2E_TEST !== 'true' && !req.nextUrl.searchParams.has('direct');

    if (useN8n) {
      try {
        const response = await fetch(process.env.N8N_WEBHOOK_URL!, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'x-n8n-signature': process.env.N8N_WEBHOOK_SECRET || ''
          },
          body: JSON.stringify({
            idempotencyKey,
            uploaderId: session.userId,
            sales: rows.map(r => ({
              username: r.username,
              hotelCode: r.hotelCode,
              period: r.period,
              amount: r.amount,
              salesCount: r.salesCount,
              transactionId: r.transactionId
            }))
          })
        });

        if (!response.ok) {
          console.error('n8n integration failed:', await response.text());
          await prisma.salesImportJob.upsert({
            where: { idempotencyKey },
            create: {
              idempotencyKey,
              status: 'FAILED',
              errorMessage: `n8n webhook responded with status ${response.status}`,
              uploadedBy: session.userId
            },
            update: {
              status: 'FAILED',
              errorMessage: `n8n webhook responded with status ${response.status}`
            }
          });
          return NextResponse.json({
            success: false,
            error: {
              code: 'INTEGRATION_ERROR',
              metadata: { status: response.status }
            }
          }, { status: 500 });
        }

        return NextResponse.json({
          success: true,
          code: 'IMPORT_ACCEPTED',
          metadata: {
            idempotencyKey,
            status: 'PROCESSING'
          }
        }, { status: 202 });
      } catch (err: any) {
        await prisma.salesImportJob.upsert({
          where: { idempotencyKey },
          create: {
            idempotencyKey,
            status: 'FAILED',
            errorMessage: err.message,
            uploadedBy: session.userId
          },
          update: {
            status: 'FAILED',
            errorMessage: err.message
          }
        });
        throw err;
      }
    }

    // Direct Import Fallback / Test mode
    const totalAmount = rows.reduce((acc, r) => acc + r.amount, 0);

    try {
      await prisma.$transaction(async (tx: any) => {
        const createdSales = [];
        for (let i = 0; i < rows.length; i++) {
          const r = rows[i];
          const user = userMap.get(r.username)!;
          const hotel = hotelMap.get(r.hotelCode)!;

          const created = await tx.salesResult.create({
            data: {
              source: 'EXCEL',
              hotelId: hotel.id,
              userId: user.id,
              period: r.period,
              amount: r.amount,
              salesCount: r.salesCount,
              idempotencyKey: `${idempotencyKey}-${i}`,
              transactionId: r.transactionId || null,
              uploadedBy: session.userId,
              status: 'PENDING'
            }
          });
          createdSales.push(created);
        }

        await tx.auditLog.create({
          data: {
            userId: session.userId,
            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: session.userId
          },
          update: {
            status: 'SUCCESS'
          }
        });
      });

      return NextResponse.json({
        success: true,
        code: 'IMPORT_SUCCESSFUL',
        metadata: {
          count: rows.length,
          totalAmount
        }
      }, { status: 201 });
    } catch (txErr: any) {
      await prisma.salesImportJob.upsert({
        where: { idempotencyKey },
        create: {
          idempotencyKey,
          status: 'FAILED',
          errorMessage: txErr.message,
          uploadedBy: session.userId
        },
        update: {
          status: 'FAILED',
          errorMessage: txErr.message
        }
      });
      throw txErr;
    }

  } catch (err: any) {
    console.error('Sales import error:', err);
    return NextResponse.json({
      success: false,
      error: {
        code: 'INTERNAL_SERVER_ERROR',
        metadata: { message: err.message }
      }
    }, { status: 500 });
  }
}, ['admin', 'analyst', 'commercial_leader']);
