import { describe, it, expect, vi, beforeEach } from "vitest";
import { z } from "zod";

import { OrganizerDefaultConferencingAppType } from "@calcom/app-store/locations";

import { getBookingData } from "./getBookingData";
import type { getEventTypeResponse } from "./getEventTypesFromDB";

// Mock the dependencies
vi.mock("@calcom/features/bookings/lib/getCalEventResponses", () => ({
  getCalEventResponses: vi.fn().mockReturnValue({
    userFieldsResponses: {},
    responses: {},
  }),
}));

vi.mock("@calcom/lib/sentryWrapper", () => ({
  withReporting: (fn: Function) => fn,
}));

const createMockEventType = (overrides: Partial<getEventTypeResponse> = {}): getEventTypeResponse => {
  return {
    id: 1,
    length: 30,
    bookingFields: [
      { name: "name", type: "name", required: true },
      { name: "email", type: "email", required: true },
      { name: "location", type: "radioInput", required: false },
    ],
    customInputs: [],
    seatsPerTimeSlot: null,
    ...overrides,
  } as getEventTypeResponse;
};

const createMockSchema = () => {
  return z.object({
    eventTypeId: z.number(),
    start: z.string(),
    end: z.string().optional(),
    timeZone: z.string(),
    language: z.string(),
    metadata: z.record(z.string()),
    responses: z.object({
      name: z.string(),
      email: z.string(),
      location: z
        .object({
          value: z.string(),
          optionValue: z.string().optional(),
        })
        .optional(),
      attendeePhoneNumber: z.string().optional(),
      guests: z.array(z.string()).optional(),
      smsReminderNumber: z.string().optional(),
      notes: z.string().optional(),
      rescheduleReason: z.string().optional(),
    }),
  });
};

describe("getBookingData", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("location extraction", () => {
    it("should ignore optionValue when location type is OrganizerDefaultConferencingAppType", async () => {
      const mockEventType = createMockEventType();
      const schema = createMockSchema();

      const reqBody = {
        eventTypeId: 1,
        start: "2024-01-15T10:00:00.000Z",
        end: "2024-01-15T10:30:00.000Z",
        timeZone: "America/New_York",
        language: "en",
        metadata: {},
        responses: {
          name: "Test User",
          email: "test@example.com",
          location: {
            value: OrganizerDefaultConferencingAppType, // "conferencing"
            optionValue: "+15551234567", // Phone number that should be ignored
          },
        },
      };

      const result = await getBookingData({
        reqBody,
        eventType: mockEventType,
        schema,
      });

      // The location should be the conferencing type, NOT the phone number
      expect(result.location).toBe(OrganizerDefaultConferencingAppType);
      expect(result.location).not.toBe("+15551234567");
    });

    it("should use optionValue for non-OrganizerDefaultConferencingAppType locations", async () => {
      const mockEventType = createMockEventType();
      const schema = createMockSchema();

      const reqBody = {
        eventTypeId: 1,
        start: "2024-01-15T10:00:00.000Z",
        end: "2024-01-15T10:30:00.000Z",
        timeZone: "America/New_York",
        language: "en",
        metadata: {},
        responses: {
          name: "Test User",
          email: "test@example.com",
          location: {
            value: "phone",
            optionValue: "+15551234567",
          },
        },
      };

      const result = await getBookingData({
        reqBody,
        eventType: mockEventType,
        schema,
      });

      // For phone location type, optionValue should be used
      expect(result.location).toBe("+15551234567");
    });

    it("should fall back to value when optionValue is empty for non-conferencing locations", async () => {
      const mockEventType = createMockEventType();
      const schema = createMockSchema();

      const reqBody = {
        eventTypeId: 1,
        start: "2024-01-15T10:00:00.000Z",
        end: "2024-01-15T10:30:00.000Z",
        timeZone: "America/New_York",
        language: "en",
        metadata: {},
        responses: {
          name: "Test User",
          email: "test@example.com",
          location: {
            value: "integrations:daily",
            optionValue: "",
          },
        },
      };

      const result = await getBookingData({
        reqBody,
        eventType: mockEventType,
        schema,
      });

      // Should fall back to value when optionValue is empty
      expect(result.location).toBe("integrations:daily");
    });

    it("should return empty string when location is not provided", async () => {
      const mockEventType = createMockEventType();
      const schema = createMockSchema();

      const reqBody = {
        eventTypeId: 1,
        start: "2024-01-15T10:00:00.000Z",
        end: "2024-01-15T10:30:00.000Z",
        timeZone: "America/New_York",
        language: "en",
        metadata: {},
        responses: {
          name: "Test User",
          email: "test@example.com",
          // No location provided
        },
      };

      const result = await getBookingData({
        reqBody,
        eventType: mockEventType,
        schema,
      });

      expect(result.location).toBe("");
    });

    it("should use OrganizerDefaultConferencingAppType value even when optionValue contains meeting URL", async () => {
      const mockEventType = createMockEventType();
      const schema = createMockSchema();

      const reqBody = {
        eventTypeId: 1,
        start: "2024-01-15T10:00:00.000Z",
        end: "2024-01-15T10:30:00.000Z",
        timeZone: "America/New_York",
        language: "en",
        metadata: {},
        responses: {
          name: "Test User",
          email: "test@example.com",
          location: {
            value: OrganizerDefaultConferencingAppType,
            optionValue: "https://meet.google.com/abc-defg-hij", // Should be ignored
          },
        },
      };

      const result = await getBookingData({
        reqBody,
        eventType: mockEventType,
        schema,
      });

      // The location should be the conferencing type, NOT the URL
      expect(result.location).toBe(OrganizerDefaultConferencingAppType);
    });
  });
});
