/**
 * Unit tests for Voice Agent routes:
 * - /api/voice-agent/webhook (POST, GET)
 * - /api/voice-agent/auth (POST, GET, PUT)
 */

// Mock dependencies BEFORE imports
jest.mock("@/lib/logger", () => ({
  logger: {
    warn: jest.fn(),
    error: jest.fn(),
    info: jest.fn(),
    debug: jest.fn(),
  },
}));

jest.mock("@/lib/db");

jest.mock("@/lib/validators/voice-agent.validator", () => ({
  callEventSchema: {
    parse: jest.fn(),
  },
}));

jest.mock("@/lib/utils/voice-agent-db", () => ({
  findUserByVoiceAgentId: jest.fn(),
  saveVoiceConversationLog: jest.fn(),
  updateVoiceConversationLog: jest.fn(),
}));

jest.mock("@/lib/services/system-settings.service", () => ({
  systemSettingsService: {
    getN8NWebhookToken: jest.fn(),
  },
}));

jest.mock("@/lib/auth", () => ({
  auth: jest.fn(),
}));

jest.mock("@/lib/api-security", () => ({
  withSecureRoute: jest.fn((handler) => handler),
}));

jest.mock("@/lib/csrf", () => ({
  validateCSRFToken: jest.fn().mockResolvedValue(true),
  CSRF_COOKIE_NAME: "csrf_token",
  CSRF_HEADER_NAME: "x-csrf-token",
}));

jest.mock("@/lib/rate-limiter", () => ({
  applyRateLimit: jest.fn().mockResolvedValue(null),
  rateLimiters: {
    voiceConfig: {},
    voiceRead: {},
  },
}));

jest.mock("@/lib/services/elevenlabs-auth.service", () => ({
  elevenLabsAuthService: {
    generateSignedUrl: jest.fn(),
    getDomainAllowlist: jest.fn(),
    setDomainAllowlist: jest.fn(),
  },
}));

jest.mock("next/server", () => ({
  NextRequest: jest.fn(),
  NextResponse: {
    json: jest.fn((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    })),
  },
}));

import { NextRequest, NextResponse } from "next/server";
import { callEventSchema } from "@/lib/validators/voice-agent.validator";
import {
  findUserByVoiceAgentId,
  saveVoiceConversationLog,
  updateVoiceConversationLog,
} from "@/lib/utils/voice-agent-db";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/db";
import { elevenLabsAuthService } from "@/lib/services/elevenlabs-auth.service";
import { z } from "zod";

// Voice agent routes not yet implemented
describe.skip("POST /api/voice-agent/webhook", () => {
  let webhookModule: any;

  beforeAll(async () => {
    webhookModule = await import("@/app/api/voice-agent/webhook/route");
  });

  beforeEach(() => {
    jest.clearAllMocks();
    (NextResponse.json as jest.Mock).mockImplementation((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    }));
    // Allow dev mode by default
    process.env.NODE_ENV = "development";
  });

  const mockRequest = (body: any, headers?: Record<string, string>) =>
    ({
      json: jest.fn().mockResolvedValue(body),
      headers: {
        get: jest.fn((key: string) => headers?.[key] || null),
      },
      nextUrl: {
        searchParams: new URLSearchParams(),
      },
    }) as unknown as NextRequest;

  it("should return 401 if webhook auth fails in production", async () => {
    process.env.NODE_ENV = "production";
    delete process.env.ELEVENLABS_WEBHOOK_SECRET;

    const response = await webhookModule.POST(mockRequest({}));
    const body = await response.json();
    expect(response.status).toBe(401);

    process.env.NODE_ENV = "development";
  });

  it("should return 400 for invalid payload", async () => {
    (callEventSchema.parse as jest.Mock).mockImplementation(() => {
      throw new z.ZodError([
        { code: "custom", message: "Invalid", path: ["call_id"] },
      ]);
    });

    const response = await webhookModule.POST(mockRequest({}));
    const body = await response.json();
    expect(response.status).toBe(400);
    expect(body.error).toBe("Validation error");
  });

  it("should process call_started event successfully", async () => {
    const event = {
      call_id: "call-123",
      agent_id: "agent-1",
      status: "started",
      start_time: "2026-01-15T10:00:00Z",
      transcript: [],
      metadata: {},
    };
    (callEventSchema.parse as jest.Mock).mockReturnValue(event);
    (findUserByVoiceAgentId as jest.Mock).mockResolvedValue("user-1");
    (prisma.conversationLog.findFirst as jest.Mock).mockResolvedValue(null);
    (saveVoiceConversationLog as jest.Mock).mockResolvedValue(undefined);

    const response = await webhookModule.POST(mockRequest(event));
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(saveVoiceConversationLog).toHaveBeenCalled();
  });

  it("should process call_ended event successfully", async () => {
    const event = {
      call_id: "call-123",
      agent_id: "agent-1",
      status: "ended",
      duration_seconds: 120,
      end_time: "2026-01-15T10:02:00Z",
      transcript: [
        { speaker: "user", text: "Hello" },
        { speaker: "agent", text: "How can I help?" },
      ],
      metadata: {},
    };
    (callEventSchema.parse as jest.Mock).mockReturnValue(event);
    (findUserByVoiceAgentId as jest.Mock).mockResolvedValue("user-1");
    (updateVoiceConversationLog as jest.Mock).mockResolvedValue(undefined);
    (prisma.workflowAnalytics.upsert as jest.Mock).mockResolvedValue({});

    const response = await webhookModule.POST(mockRequest(event));
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(updateVoiceConversationLog).toHaveBeenCalled();
  });

  it("should handle unknown agent gracefully", async () => {
    const event = {
      call_id: "call-999",
      agent_id: "unknown-agent",
      status: "started",
      transcript: [],
      metadata: {},
    };
    (callEventSchema.parse as jest.Mock).mockReturnValue(event);
    (findUserByVoiceAgentId as jest.Mock).mockResolvedValue(null);

    const response = await webhookModule.POST(mockRequest(event));
    const body = await response.json();
    expect(body.success).toBe(true);
    // Should still succeed but not save conversation
    expect(saveVoiceConversationLog).not.toHaveBeenCalled();
  });
});

// Voice agent routes not yet implemented
describe.skip("GET /api/voice-agent/webhook", () => {
  let webhookModule: any;

  beforeAll(async () => {
    webhookModule = await import("@/app/api/voice-agent/webhook/route");
  });

  beforeEach(() => {
    jest.clearAllMocks();
    (NextResponse.json as jest.Mock).mockImplementation((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    }));
  });

  it("should return challenge for verification", async () => {
    const request = {
      nextUrl: {
        searchParams: new URLSearchParams({ challenge: "test-challenge-123" }),
      },
    } as unknown as NextRequest;

    const response = await webhookModule.GET(request);
    const body = await response.json();
    expect(body.challenge).toBe("test-challenge-123");
  });

  it("should return webhook info without challenge", async () => {
    const request = {
      nextUrl: {
        searchParams: new URLSearchParams(),
      },
    } as unknown as NextRequest;

    const response = await webhookModule.GET(request);
    const body = await response.json();
    expect(body.message).toBe("Voice agent webhook endpoint");
    expect(body.version).toBe("1.0.0");
  });
});

// Voice agent routes not yet implemented
describe.skip("/api/voice-agent/auth", () => {
  let authModule: any;

  beforeAll(async () => {
    authModule = await import("@/app/api/voice-agent/auth/route");
  });

  beforeEach(() => {
    jest.clearAllMocks();
    (NextResponse.json as jest.Mock).mockImplementation((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    }));
  });

  const mockAuthRequest = (method = "POST") =>
    ({
      method,
      headers: { get: jest.fn(() => null) },
      cookies: { get: jest.fn(() => undefined) },
      json: jest.fn().mockResolvedValue({}),
    }) as unknown as NextRequest;

  describe("POST - Generate signed URL", () => {
    it("should return 401 if not authenticated", async () => {
      (auth as jest.Mock).mockResolvedValue(null);

      const response = await authModule.POST(mockAuthRequest());
      const body = await response.json();
      expect(response.status).toBe(401);
    });

    it("should return 404 if no voice agent configured", async () => {
      (auth as jest.Mock).mockResolvedValue({
        user: { email: "test@test.com" },
      });
      (prisma.users.findUnique as jest.Mock).mockResolvedValue({
        id: "u1",
        voiceAgentId: null,
      });

      const response = await authModule.POST(mockAuthRequest());
      const body = await response.json();
      expect(response.status).toBe(404);
      expect(body.error).toBe("No voice agent configured");
    });

    it("should generate signed URL successfully", async () => {
      (auth as jest.Mock).mockResolvedValue({
        user: { email: "test@test.com" },
      });
      (prisma.users.findUnique as jest.Mock).mockResolvedValue({
        id: "u1",
        voiceAgentId: "agent-1",
      });
      (elevenLabsAuthService.generateSignedUrl as jest.Mock).mockResolvedValue({
        url: "https://signed-url.com",
        expiresAt: "2026-01-15T11:00:00Z",
      });

      const response = await authModule.POST(mockAuthRequest());
      const body = await response.json();
      expect(body.success).toBe(true);
      expect(body.data.url).toBe("https://signed-url.com");
    });
  });

  describe("GET - Get domain allowlist", () => {
    it("should return 401 if not authenticated", async () => {
      (auth as jest.Mock).mockResolvedValue(null);

      const response = await authModule.GET(mockAuthRequest());
      const body = await response.json();
      expect(response.status).toBe(401);
    });

    it("should return domain allowlist", async () => {
      (auth as jest.Mock).mockResolvedValue({
        user: { email: "test@test.com" },
      });
      (prisma.users.findUnique as jest.Mock).mockResolvedValue({
        id: "u1",
        voiceAgentId: "agent-1",
      });
      (elevenLabsAuthService.getDomainAllowlist as jest.Mock).mockResolvedValue(
        {
          domains: ["https://example.com"],
        },
      );

      const response = await authModule.GET(mockAuthRequest());
      const body = await response.json();
      expect(body.success).toBe(true);
      expect(body.data.domains).toContain("https://example.com");
    });
  });
});
