/**
 * N8N Error Webhook Callback
 *
 * Receives error reports from N8N workflows for:
 * - Workflow execution failures
 * - API integration errors
 * - Rate limit hits
 * - Authentication failures
 *
 * Stores errors for debugging and user notification.
 */

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 { applyRateLimit, rateLimiters, getClientIdentifier } from "@/lib/rate-limiter";

// Request validation schema
const errorPayloadSchema = z.object({
  auth_token: z.string().min(1),
  user_id: z.string().optional(), // May not have user context for some errors
  workflow_id: z.string().optional(),
  workflow_name: z.string().optional(),
  execution_id: z.string().optional(),
  error: z.object({
    type: z.enum([
      "workflow_failure",
      "api_error",
      "rate_limit",
      "auth_failure",
      "validation_error",
      "timeout",
      "unknown",
    ]),
    code: z.string().optional(),
    message: z.string(),
    stack: z.string().optional(),
    service: z.string().optional(), // e.g., 'whatsapp', 'elevenlabs', 'openai'
  }),
  context: z
    .object({
      node_name: z.string().optional(),
      node_type: z.string().optional(),
      input_data: z.unknown().optional(),
      timestamp: z.string().optional(),
    })
    .optional(),
  severity: z.enum(["low", "medium", "high", "critical"]).default("medium"),
  should_notify_user: z.boolean().default(false),
});

interface ErrorCallbackResponse {
  success: boolean;
  error_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 error webhook rate limit exceeded", {
      ip: getClientIdentifier(request),
    });
    return rateLimitResponse;
  }

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

    if (!validationResult.success) {
      logger.warn("N8N error callback - invalid payload", {
        errors: validationResult.error.errors,
      });
      return NextResponse.json<ErrorCallbackResponse>(
        {
          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 error callback - invalid auth token");
      return NextResponse.json<ErrorCallbackResponse>(
        { success: false, error: "Invalid authentication token" },
        { status: 401 },
      );
    }

    // Log the error with full context
    const logLevel = payload.severity === "critical" ? "error" : "warn";
    logger[logLevel]("N8N workflow error reported", {
      user_id: payload.user_id,
      workflow_id: payload.workflow_id,
      workflow_name: payload.workflow_name,
      execution_id: payload.execution_id,
      error_type: payload.error.type,
      error_code: payload.error.code,
      error_message: payload.error.message,
      service: payload.error.service,
      severity: payload.severity,
      context: payload.context,
    });

    // Store error in database for tracking
    const errorRecord = await prisma.workflowError.create({
      data: {
        userId: payload.user_id,
        workflowId: payload.workflow_id,
        workflowName: payload.workflow_name,
        executionId: payload.execution_id,
        errorType: payload.error.type,
        errorCode: payload.error.code,
        errorMessage: payload.error.message,
        errorStack: payload.error.stack,
        service: payload.error.service,
        severity: payload.severity,
        context: payload.context || {},
        resolvedAt: null,
      },
    });

    // Create notification for user if requested and user exists
    if (payload.should_notify_user && payload.user_id) {
      await createErrorNotification(
        payload.user_id,
        errorRecord.id,
        payload.error.type,
        payload.error.message,
        payload.severity,
      );
    }

    // For critical errors, also send alert to system admins
    if (payload.severity === "critical") {
      await alertSystemAdmins(payload, errorRecord.id);
    }

    // Update workflow status if this is a recurring error
    if (payload.user_id && payload.workflow_id) {
      await checkAndUpdateWorkflowHealth(payload.user_id, payload.workflow_id);
    }

    return NextResponse.json<ErrorCallbackResponse>({
      success: true,
      error_id: errorRecord.id,
    });
  } catch (error) {
    // Even if DB fails, we still log to console/logs
    logger.error("N8N error callback - failed to process", { error });
    return NextResponse.json<ErrorCallbackResponse>(
      { success: false, error: "Internal server error" },
      { status: 500 },
    );
  }
}

/**
 * Create notification for user about workflow error
 */
async function createErrorNotification(
  userId: string,
  errorId: string,
  errorType: string,
  errorMessage: string,
  severity: string,
) {
  try {
    const titles: Record<string, string> = {
      workflow_failure: "Workflow Error",
      api_error: "Integration Error",
      rate_limit: "Rate Limit Reached",
      auth_failure: "Authentication Failed",
      validation_error: "Data Validation Error",
      timeout: "Request Timeout",
      unknown: "System Error",
    };

    await prisma.notifications.create({
      data: {
        userId,
        type: "workflow_error",
        title: titles[errorType] || "Workflow Error",
        message: errorMessage.substring(0, 200),
        actionUrl: `/dashboard?tab=settings&error=${errorId}`,
        metadata: {
          error_id: errorId,
          error_type: errorType,
          severity,
        },
        priority: severity === "critical" ? "high" : "normal",
      },
    });
  } catch (error) {
    logger.error("Failed to create error notification", {
      error,
      userId,
      errorId,
    });
  }
}

/**
 * Alert system administrators for critical errors
 */
async function alertSystemAdmins(
  payload: z.infer<typeof errorPayloadSchema>,
  errorId: string,
) {
  try {
    // Create admin notification
    await prisma.admin_notifications.create({
      data: {
        type: "critical_workflow_error",
        title: `Critical Error: ${payload.error.type}`,
        message: `User: ${payload.user_id || "Unknown"}\nWorkflow: ${payload.workflow_name || payload.workflow_id || "Unknown"}\nError: ${payload.error.message}`,
        metadata: {
          error_id: errorId,
          user_id: payload.user_id,
          workflow_id: payload.workflow_id,
          execution_id: payload.execution_id,
          service: payload.error.service,
        },
        isRead: false,
      },
    });

    logger.warn("Critical N8N error - admin notification created", {
      error_id: errorId,
      user_id: payload.user_id,
    });
  } catch (error) {
    logger.error("Failed to alert system admins", { error });
  }
}

/**
 * Check for recurring errors and update workflow health status
 */
async function checkAndUpdateWorkflowHealth(
  userId: string,
  workflowId: string,
) {
  try {
    // Count recent errors (last 24 hours)
    const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);

    const recentErrorCount = await prisma.workflowError.count({
      where: {
        userId,
        workflowId,
        createdAt: { gte: twentyFourHoursAgo },
      },
    });

    // If too many errors, mark workflow as unhealthy
    if (recentErrorCount >= 10) {
      await prisma.userWorkflow.updateMany({
        where: {
          userId,
          n8nWorkflowId: workflowId,
        },
        data: {
          healthStatus: "unhealthy",
          lastErrorAt: new Date(),
          errorCount: recentErrorCount,
        },
      });

      logger.warn("Workflow marked as unhealthy due to recurring errors", {
        userId,
        workflowId,
        errorCount: recentErrorCount,
      });
    }
  } catch (error) {
    logger.error("Failed to check workflow health", {
      error,
      userId,
      workflowId,
    });
  }
}

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