/**
 * Voice Agent Webhook API
 *
 * POST /api/voice-agent/webhook
 * Receives call events from ElevenLabs (call_started, call_ended, call_failed)
 * Forwards events to N8N for processing and logs transcripts
 */

import { NextRequest, NextResponse } from "next/server";
import { logger } from "@/lib/logger";
import { callEventSchema } from "@/lib/validators/voice-agent.validator";
import {
  findUserByVoiceAgentId,
  saveVoiceConversationLog,
  updateVoiceConversationLog,
} from "@/lib/utils/voice-agent-db";
import { systemSettingsService } from "@/lib/services/system-settings.service";
import { z } from "zod";
import { getDataSource } from "@/lib/data-source";

/**
 * Verify webhook authenticity
 * In production, you should verify the webhook signature from ElevenLabs
 */
function verifyWebhookAuth(request: NextRequest): boolean {
  // Option 1: Shared secret in header
  const authHeader = request.headers.get("x-elevenlabs-signature");
  const webhookSecret = process.env.ELEVENLABS_WEBHOOK_SECRET;

  if (webhookSecret && authHeader) {
    return authHeader === webhookSecret;
  }

  // Option 2: IP whitelist (ElevenLabs IPs)
  // const clientIP = request.headers.get('x-forwarded-for') || request.ip;
  // return ELEVENLABS_IP_WHITELIST.includes(clientIP);

  // For development: Allow all (remove in production!)
  if (process.env.NODE_ENV === "development") {
    return true;
  }

  return false;
}

/**
 * Forward event to N8N webhook
 */
async function forwardToN8N(event: any): Promise<void> {
  const n8nWebhookUrl = process.env.N8N_VOICE_WEBHOOK_URL;

  if (!n8nWebhookUrl) {
    logger.warn("N8N_VOICE_WEBHOOK_URL not configured, skipping forward");
    return;
  }

  try {
    // Get auth token from database or env fallback
    const n8nAuthToken = await systemSettingsService.getN8NWebhookToken();

    const headers: HeadersInit = {
      "Content-Type": "application/json",
    };

    if (n8nAuthToken) {
      headers["Authorization"] = `Bearer ${n8nAuthToken}`;
    }

    const response = await fetch(n8nWebhookUrl, {
      method: "POST",
      headers,
      body: JSON.stringify(event),
    });

    if (!response.ok) {
      logger.error(
        "Failed to forward event to N8N",
        new Error(response.statusText),
        {
          status: response.status,
          callId: event.call_id,
        },
      );
    } else {
      logger.info("Successfully forwarded event to N8N", {
        callId: event.call_id,
        status: event.status,
      });
    }
  } catch (error) {
    logger.error("Error forwarding event to N8N", error, {
      callId: event.call_id,
    });
  }
}

/**
 * Handle conversation log based on event status
 */
async function handleConversationLog(
  event: any,
  userId: string,
): Promise<void> {
  try {
    if (event.status === "started") {
      // Create new conversation log
      await saveVoiceConversationLog({
        userId,
        callId: event.call_id,
        agentId: event.agent_id,
        customerPhone: event.user_phone,
        transcript: event.transcript,
        status: event.status,
        metadata: {
          startTime: event.start_time,
          ...event.metadata,
        },
      });
    } else if (event.status === "ended" || event.status === "failed") {
      // Update existing conversation log with final transcript and metadata
      await updateVoiceConversationLog(event.call_id, {
        transcript: event.transcript,
        status: event.status,
        metadata: {
          endTime: event.end_time,
          durationSeconds: event.duration_seconds,
          ...event.metadata,
        },
      });
    }
  } catch (error) {
    logger.error("Error handling conversation log", error, {
      callId: event.call_id,
      status: event.status,
    });
  }
}

/**
 * POST /api/voice-agent/webhook
 * Handle call events from ElevenLabs
 */
export async function POST(request: NextRequest) {
  try {
    // Verify webhook authentication
    if (!verifyWebhookAuth(request)) {
      logger.warn("Unauthorized webhook request", {
        ip: request.headers.get("x-forwarded-for") || "unknown",
      });
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    // Parse and validate request body
    const body = await request.json();
    const event = callEventSchema.parse(body);

    logger.info("Received voice agent webhook event", {
      callId: event.call_id,
      agentId: event.agent_id,
      status: event.status,
    });

    // ── Convex data-source branch ──────────────────────────────────────
    if (getDataSource("voice_agents") === "convex") {
      try {
        const { convexQuery, convexMutation } =
          await import("@/lib/convex-client");

        // Find user by voiceAgentId in Convex
        const cvxUser = (await convexQuery(
          "voice_agents/queries:getUserByVoiceAgentId",
          {
            voiceAgentId: event.agent_id,
          },
        )) as { prismaId?: string; _id: string } | null;

        const convexUserId = cvxUser?.prismaId ?? cvxUser?._id ?? null;

        if (!convexUserId) {
          logger.warn("No user found for agent ID (Convex)", {
            agentId: event.agent_id,
            callId: event.call_id,
          });
        } else {
          // Handle conversation logging via Convex
          if (event.status === "started") {
            const messages =
              event.transcript?.map(
                (msg: {
                  speaker: string;
                  text: string;
                  timestamp: string;
                }) => ({
                  role: msg.speaker === "agent" ? "assistant" : "user",
                  content: msg.text,
                  timestamp: msg.timestamp,
                }),
              ) || [];

            await convexMutation(
              "voice_agents/mutations:createConversationLog",
              {
                userId: convexUserId,
                platform: "voice",
                customerPhone: event.user_phone || undefined,
                metadata: {
                  callId: event.call_id,
                  agentId: event.agent_id,
                  status: event.status,
                  startTime: event.start_time,
                  ...event.metadata,
                },
              },
            );
          } else if (event.status === "ended" || event.status === "failed") {
            const messages =
              event.transcript?.map(
                (msg: {
                  speaker: string;
                  text: string;
                  timestamp: string;
                }) => ({
                  role: msg.speaker === "agent" ? "assistant" : "user",
                  content: msg.text,
                  timestamp: msg.timestamp,
                }),
              ) || [];

            await convexMutation(
              "voice_agents/mutations:updateConversationLog",
              {
                callId: event.call_id,
                messages: messages.length > 0 ? messages : undefined,
                status: event.status,
                metadata: {
                  endTime: event.end_time,
                  durationSeconds: event.duration_seconds,
                  ...event.metadata,
                },
              },
            );
          }
        }

        // Log event details
        switch (event.status) {
          case "started":
            logger.info("Call started (Convex)", {
              callId: event.call_id,
              agentId: event.agent_id,
              userId: convexUserId,
            });
            break;
          case "ended":
            logger.info("Call ended (Convex)", {
              callId: event.call_id,
              agentId: event.agent_id,
              durationSeconds: event.duration_seconds,
              userId: convexUserId,
            });
            break;
          case "failed":
            logger.warn("Call failed (Convex)", {
              callId: event.call_id,
              agentId: event.agent_id,
              userId: convexUserId,
            });
            break;
          default:
            logger.warn("Unknown call status (Convex)", {
              callId: event.call_id,
              status: event.status,
            });
        }

        // Forward to N8N (non-blocking)
        forwardToN8N({ ...event, userId: convexUserId }).catch((error) => {
          logger.error("Failed to forward to N8N", error);
        });

        return NextResponse.json(
          { success: true, message: "Event received and processed" },
          { status: 200 },
        );
      } catch (convexError) {
        console.error("[Convex fallback] voice_agents webhook:", convexError);
        // Fall through to Prisma path
      }
    }

    // ── Prisma path (default) ─────────────────────────────────────────
    // Find user associated with this agent
    const userId = await findUserByVoiceAgentId(event.agent_id);

    if (!userId) {
      logger.warn("No user found for agent ID", {
        agentId: event.agent_id,
        callId: event.call_id,
      });
      // Still forward to N8N even if user not found
    } else {
      // Handle conversation logging
      await handleConversationLog(event, userId);
    }

    // Log event details
    switch (event.status) {
      case "started":
        logger.info("Call started", {
          callId: event.call_id,
          agentId: event.agent_id,
          userId,
        });
        break;

      case "ended":
        logger.info("Call ended", {
          callId: event.call_id,
          agentId: event.agent_id,
          durationSeconds: event.duration_seconds,
          userId,
        });
        break;

      case "failed":
        logger.warn("Call failed", {
          callId: event.call_id,
          agentId: event.agent_id,
          userId,
        });
        break;

      default:
        logger.warn("Unknown call status", {
          callId: event.call_id,
          status: event.status,
        });
    }

    // Forward to N8N (non-blocking)
    forwardToN8N({
      ...event,
      userId,
    }).catch((error) => {
      logger.error("Failed to forward to N8N", error);
    });

    // Return success response to ElevenLabs
    return NextResponse.json(
      {
        success: true,
        message: "Event received and processed",
      },
      { status: 200 },
    );
  } catch (error) {
    // Handle validation errors
    if (error instanceof z.ZodError) {
      logger.error("Invalid webhook payload", error);
      return NextResponse.json(
        {
          error: "Validation error",
          message: "Invalid event payload",
          details: error.errors,
        },
        { status: 400 },
      );
    }

    // Generic error
    logger.error("Error processing voice agent webhook", error);
    return NextResponse.json(
      {
        error: "Internal server error",
        message: "Failed to process webhook event",
      },
      { status: 500 },
    );
  }
}

/**
 * GET /api/voice-agent/webhook
 * Webhook verification endpoint (if needed by ElevenLabs)
 */
export async function GET(request: NextRequest) {
  const challenge = request.nextUrl.searchParams.get("challenge");

  if (challenge) {
    // Return challenge for webhook verification
    return NextResponse.json({ challenge }, { status: 200 });
  }

  return NextResponse.json(
    {
      message: "Voice agent webhook endpoint",
      version: "1.0.0",
    },
    { status: 200 },
  );
}
