/**
 * N8N Lead Capture Webhook Callback
 *
 * Receives leads from various sources via N8N workflows:
 * - QR code scans
 * - Social media messages
 * - Form submissions
 * - WhatsApp lead gen ads
 */

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { logger } from "@/lib/logger";
import { systemSettingsService } from "@/lib/services/system-settings.service";
import { z } from "zod";
import { createId } from "@paralleldrive/cuid2";
import { applyRateLimit, rateLimiters, getClientIdentifier } from "@/lib/rate-limiter";

// Request validation schema
const leadPayloadSchema = z.object({
  auth_token: z.string().min(1),
  user_id: z.string().min(1),
  source: z.enum([
    "qr_code",
    "social",
    "form",
    "whatsapp_ad",
    "website",
    "referral",
  ]),
  campaign_id: z.string().optional(),
  lead: z.object({
    name: z.string().min(1),
    phone: z.string().optional(),
    email: z.string().email().optional(),
    company: z.string().optional(),
    interest: z.string().optional(),
    notes: z.string().optional(),
    custom_fields: z.record(z.unknown()).optional(),
  }),
  metadata: z
    .object({
      utm_source: z.string().optional(),
      utm_medium: z.string().optional(),
      utm_campaign: z.string().optional(),
      referrer_url: z.string().optional(),
      landing_page: z.string().optional(),
      device_type: z.string().optional(),
      location: z.string().optional(),
    })
    .optional(),
});

interface LeadCallbackResponse {
  success: boolean;
  lead_id?: string;
  error?: string;
}

export async function POST(request: NextRequest) {
  // Rate limit webhook requests (100/min per IP)
  const rateLimitResponse = await applyRateLimit(request, rateLimiters.webhookGeneral);
  if (rateLimitResponse) {
    logger.warn("N8N lead webhook rate limit exceeded", {
      ip: getClientIdentifier(request),
    });
    return rateLimitResponse;
  }

  try {
    // Parse and validate request body
    const body = await request.json();
    const validationResult = leadPayloadSchema.safeParse(body);

    if (!validationResult.success) {
      logger.warn("N8N lead callback - invalid payload", {
        errors: validationResult.error.errors,
      });
      return NextResponse.json<LeadCallbackResponse>(
        {
          success: false,
          error: "Invalid payload: " + validationResult.error.errors[0].message,
        },
        { status: 400 },
      );
    }

    const payload = validationResult.data;

    // Validate auth token (from database or env fallback)
    const isValidToken = await systemSettingsService.validateN8NToken(
      payload.auth_token,
    );
    if (!isValidToken) {
      logger.warn("N8N lead callback - invalid auth token", {
        user_id: payload.user_id,
      });
      return NextResponse.json<LeadCallbackResponse>(
        { success: false, error: "Invalid authentication token" },
        { status: 401 },
      );
    }

    // Verify user exists and has active subscription
    const user = await prisma.users.findUnique({
      where: { id: payload.user_id },
      include: {
        subscriptions: {
          where: { status: { in: ["active", "trialing"] } },
          take: 1,
        },
      },
    });

    if (!user || !user.isActive) {
      logger.warn("N8N lead callback - user not found or inactive", {
        user_id: payload.user_id,
      });
      return NextResponse.json<LeadCallbackResponse>(
        { success: false, error: "User not found or inactive" },
        { status: 404 },
      );
    }

    if (user.subscriptions.length === 0) {
      logger.warn("N8N lead callback - no active subscription", {
        user_id: payload.user_id,
      });
      return NextResponse.json<LeadCallbackResponse>(
        { success: false, error: "No active subscription" },
        { status: 403 },
      );
    }

    // Check for duplicate lead (same phone or email within 24 hours)
    const existingLead = await checkDuplicateLead(
      payload.user_id,
      payload.lead.phone,
      payload.lead.email,
    );

    if (existingLead) {
      logger.info("N8N lead callback - duplicate lead detected", {
        user_id: payload.user_id,
        existing_lead_id: existingLead.id,
      });
      return NextResponse.json<LeadCallbackResponse>({
        success: true,
        lead_id: existingLead.id,
      });
    }

    // Create the lead
    const leadId = createId();

    logger.info("N8N lead callback - created lead", {
      lead_id: lead.id,
      user_id: payload.user_id,
      source: payload.source,
    });

    // Update workflow analytics
    await updateLeadAnalytics(payload.user_id, payload.source);

    // Create notification for user
    await createLeadNotification(
      payload.user_id,
      lead.id,
      payload.lead.name,
      payload.source,
    );

    // Update or create customer record if phone provided
    if (payload.lead.phone) {
      await upsertCustomerFromLead(
        payload.user_id,
        payload.lead.name,
        payload.lead.phone,
        payload.lead.email,
      );
    }

    return NextResponse.json<LeadCallbackResponse>({
      success: true,
      lead_id: lead.id,
    });
  } catch (error) {
    logger.error("N8N lead callback error", { error });
    return NextResponse.json<LeadCallbackResponse>(
      { success: false, error: "Internal server error" },
      { status: 500 },
    );
  }
}

/**
 * Check for duplicate lead within 24 hours
 */
async function checkDuplicateLead(
  userId: string,
  phone?: string,
  email?: string,
): Promise<{ id: string } | null> {
  if (!phone && !email) return null;

  const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);

  const conditions = [];
  if (phone) conditions.push({ phone });
  if (email) conditions.push({ email });

  try {
    const existing = await prisma.leads.findFirst({
      where: {
        userId,
        createdAt: { gte: twentyFourHoursAgo },
        OR: conditions,
      },
      select: { id: true },
    });

    return existing;
  } catch {
    return null;
  }
}

/**
 * Calculate a basic lead score based on data completeness and source
 */
function calculateLeadScore(
  payload: z.infer<typeof leadPayloadSchema>,
): number {
  let score = 0;

  // Base score by source (some sources are higher intent)
  const sourceScores: Record<string, number> = {
    form: 30,
    whatsapp_ad: 35,
    qr_code: 25,
    social: 20,
    website: 15,
    referral: 40,
  };
  score += sourceScores[payload.source] || 10;

  // Data completeness
  if (payload.lead.phone) score += 15;
  if (payload.lead.email) score += 15;
  if (payload.lead.company) score += 10;
  if (payload.lead.interest) score += 10;

  // Campaign tracking indicates intent
  if (payload.campaign_id) score += 5;
  if (payload.metadata?.utm_campaign) score += 5;

  return Math.min(score, 100);
}

/**
 * Update workflow analytics for leads
 */
async function updateLeadAnalytics(userId: string, source: string) {
  try {
    const today = new Date();
    today.setHours(0, 0, 0, 0);

    // Map source to workflow type
    const workflowType =
      source === "whatsapp_ad" || source === "social" ? "whatsapp" : "ai_agent";

    await prisma.workflowAnalytics.upsert({
      where: {
        userId_workflowType_date: {
          userId,
          workflowType,
          date: today,
        },
      },
      create: {
        userId,
        workflowType,
        date: today,
        leadsGenerated: 1,
      },
      update: {
        leadsGenerated: { increment: 1 },
      },
    });
  } catch (error) {
    logger.error("Failed to update lead analytics", {
      error,
      userId,
      source,
    });
  }
}

/**
 * Create notification for new lead
 */
async function createLeadNotification(
  userId: string,
  leadId: string,
  leadName: string,
  source: string,
) {
  try {
    const sourceLabels: Record<string, string> = {
      qr_code: "QR Code",
      social: "Social Media",
      form: "Form",
      whatsapp_ad: "WhatsApp Ad",
      website: "Website",
      referral: "Referral",
    };

    await prisma.notifications.create({
      data: {
        userId,
        type: "new_lead",
        title: "New Lead Captured",
        message: `${leadName} via ${sourceLabels[source] || source}`,
        actionUrl: `/dashboard?tab=leads&lead=${leadId}`,
        metadata: {
          lead_id: leadId,
          lead_name: leadName,
          source,
        },
      },
    });
  } catch (error) {
    logger.error("Failed to create lead notification", {
      error,
      userId,
      leadId,
    });
  }
}

/**
 * Upsert customer record from lead
 */
async function upsertCustomerFromLead(
  userId: string,
  name: string,
  phone: string,
  email?: string,
) {
  try {
    await prisma.customers.upsert({
      where: {
        userId_phone: {
          userId,
          phone,
        },
      },
      create: {
        userId,
        name,
        phone,
        email,
        source: "lead",
      },
      update: {
        name,
        email: email || undefined,
      },
    });
  } catch (error) {
    logger.error("Failed to upsert customer from lead", {
      error,
      userId,
      phone,
    });
  }
}

// Only allow POST method
export async function GET() {
  return NextResponse.json({ error: "Method not allowed" }, { status: 405 });
}
