import type { TFunction } from "i18next";
import z from "zod";

import { guessEventLocationType } from "@calcom/app-store/locations";
import type { Prisma } from "@calcom/prisma/client";

export const nameObjectSchema = z.object({
  firstName: z.string(),
  lastName: z.string().optional(),
});

function parseName(name: z.infer<typeof nameObjectSchema> | string | undefined) {
  if (typeof name === "string") return name;
  else if (typeof name === "object" && nameObjectSchema.parse(name))
    return `${name.firstName} ${name.lastName}`.trim();
  else return "Nameless";
}

export type EventNameObjectType = {
  attendeeName: z.infer<typeof nameObjectSchema> | string;
  eventType: string;
  eventName?: string | null;
  teamName?: string | null;
  host: string;
  location?: string | null;
  eventDuration: number;
  bookingFields?: Prisma.JsonObject | null;
  t: TFunction;
};

export function getEventName(eventNameObj: EventNameObjectType, forAttendeeView = false) {
  const attendeeName = parseName(eventNameObj.attendeeName);

  if (!eventNameObj.eventName)
    return eventNameObj.t("event_between_users", {
      eventName: eventNameObj.eventType,
      host: eventNameObj.teamName || eventNameObj.host,
      attendeeName,
      interpolation: {
        escapeValue: false,
      },
    });

  let eventName = eventNameObj.eventName;
  let locationString = eventNameObj.location || "";

  if (eventNameObj.eventName.includes("{Location}") || eventNameObj.eventName.includes("{LOCATION}")) {
    const eventLocationType = guessEventLocationType(eventNameObj.location);
    if (eventLocationType) {
      locationString = eventLocationType.label;
    }
    eventName = eventName.replace("{Location}", locationString);
    eventName = eventName.replace("{LOCATION}", locationString);
  }

  let dynamicEventName = eventName
    // Need this for compatibility with older event names
    .replaceAll("{Event type title}", eventNameObj.eventType)
    .replaceAll("{Scheduler}", attendeeName)
    .replaceAll("{Organiser}", eventNameObj.host)
    .replaceAll("{Organiser first name}", eventNameObj.host.split(" ")[0])
    .replaceAll("{USER}", attendeeName)
    .replaceAll("{ATTENDEE}", attendeeName)
    .replaceAll("{HOST}", eventNameObj.host)
    .replaceAll("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : attendeeName)
    .replaceAll("{Event duration}", `${String(eventNameObj.eventDuration)} mins`)
    .replaceAll(
      "{Scheduler first name}",
      attendeeName === eventNameObj.t("scheduler") ? "{Scheduler first name}" : attendeeName.split(" ")[0]
    );

  const { bookingFields } = eventNameObj || {};
  const { name } = bookingFields || {};

  if (name && typeof name === "object" && !Array.isArray(name) && typeof name.lastName === "string") {
    dynamicEventName = dynamicEventName.replaceAll("{Scheduler last name}", name.lastName.toString());
  }

  const customInputvariables = dynamicEventName.match(/\{(.+?)}/g)?.map((variable) => {
    return variable.replace("{", "").replace("}", "");
  });

  customInputvariables?.forEach((variable) => {
    if (!eventNameObj.bookingFields) return;

    const bookingFieldValue = eventNameObj.bookingFields[variable as keyof typeof eventNameObj.bookingFields];

    if (bookingFieldValue) {
      let fieldValue;

      if (typeof bookingFieldValue === "object") {
        if ("value" in bookingFieldValue) {
          const valueAsString = bookingFieldValue.value?.toString();
          fieldValue =
            variable === "location"
              ? guessEventLocationType(valueAsString)?.label || valueAsString
              : valueAsString;
        } else if (variable === "name" && "firstName" in bookingFieldValue) {
          const lastName = "lastName" in bookingFieldValue ? bookingFieldValue.lastName : "";
          fieldValue = `${bookingFieldValue.firstName} ${lastName}`.trim();
        }
      } else {
        fieldValue = bookingFieldValue.toString();
      }

      dynamicEventName = dynamicEventName.replace(`{${variable}}`, fieldValue || "");
    } else {
      dynamicEventName = dynamicEventName.replace(`{${variable}}`, "");
    }
  });

  return dynamicEventName;
}

export function updateHostInEventName(eventName: string, oldHost: string, newHost: string) {
  const oldParts = oldHost.trim().split(/\s+/);
  const newParts = newHost.trim().split(/\s+/);

  // Handle cases where names might have different number of parts
  const oldFirst = oldParts[0];
  const oldLast = oldParts.slice(1).join(" ");
  const newFirst = newParts[0];
  const newLast = newParts.slice(1).join(" ");

  const formats = [
    // Full name patterns (prioritize these first)
    ...(oldLast
      ? [
          {
            pattern: `${oldFirst}.${oldLast}`,
            replacement: newLast ? `${newFirst}.${newLast}` : newFirst,
          },
          {
            pattern: `${oldFirst}-${oldLast}`,
            replacement: newLast ? `${newFirst}-${newLast}` : newFirst,
          },
          {
            pattern: `${oldFirst}_${oldLast}`,
            replacement: newLast ? `${newFirst}_${newLast}` : newFirst,
          },
          {
            pattern: `${oldFirst} ${oldLast}`,
            replacement: newLast ? `${newFirst} ${newLast}` : newFirst,
          },
        ]
      : []),
    // First name only (last to avoid partial matches)
    {
      pattern: oldFirst,
      replacement: newFirst,
    },
  ];

  let updatedEventName = eventName;

  for (const { pattern, replacement } of formats) {
    // Escape special regex characters in the pattern
    const escapedPattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    const regex = new RegExp(`\\b${escapedPattern}\\b`, "gi");

    if (regex.test(updatedEventName)) {
      updatedEventName = updatedEventName.replace(regex, replacement);
      return updatedEventName;
    }
  }

  return updatedEventName;
}

export const validateCustomEventName = (value: string, bookingFields?: Prisma.JsonObject | null) => {
  let customInputVariables: string[] = [];
  if (bookingFields) {
    customInputVariables = Object.keys(bookingFields).map((customInput) => {
      return `{${customInput}}`;
    });
  }

  const validVariables = customInputVariables.concat([
    "{Event type title}",
    "{Organiser}",
    "{Scheduler}",
    "{Location}",
    "{Organiser first name}",
    "{Scheduler first name}",
    "{Scheduler last name}",
    "{Event duration}",
    //allowed for fallback reasons
    "{LOCATION}",
    "{HOST/ATTENDEE}",
    "{HOST}",
    "{ATTENDEE}",
    "{USER}",
  ]);
  const matches = value.match(/\{([^}]+)\}/g);
  if (matches?.length) {
    for (const item of matches) {
      if (!validVariables.includes(item)) {
        return item;
      }
    }
  }

  return true;
};
