import { h as deleteScheduledEmailReminder, j as deleteScheduledSMSReminder, k as deleteScheduledAIPhoneCall, a as isSMSOrWhatsappAction, c as scheduleEmailReminder, s as scheduleSMSReminder, e as scheduleWhatsappReminder, g as scheduleAIPhoneCall, l as emailReminderTemplate, m as emailRatingTemplate } from "./internal-team-billing--m4l_O5P.js";
import { p as prisma, l as logger, M as MembershipRole, f as WorkflowMethods, aw as SENDER_ID, i as SENDER_NAME, B as BookingStatus, W as WorkflowTriggerEvents, h as WorkflowActions, S as SchedulingType, E as EventTypeMetaDataSchema, g as getTranslation, ax as WorkflowTemplates } from "./i18n-VAwx2uzJ.js";
import { l as SMS_REMINDER_NUMBER_FIELD, C as CAL_AI_AGENT_PHONE_NUMBER_FIELD } from "./CalEventParser-yX6oM9Dn.js";
import { g as getBookingFieldsWithSystemFields, h as hasFilter, a as getBookerBaseUrl, b as getSmsReminderNumberSource, c as getSmsReminderNumberField, d as getAIAgentCallPhoneNumberSource, e as getAIAgentCallPhoneNumberField } from "./hasFilter-gcDb2r-w.js";
import { F as FeaturesRepository } from "./features.repository-X0S5Zedc.js";
import { M as MembershipRepository } from "./membership-saDLcnY4.js";
import { g as getOrgIdFromMemberOrTeamId } from "./getOrgIdFromMemberOrTeamId-mAw0N41v.js";
import z__default, { z } from "zod";
import { H as HttpError } from "./http-error-RJXCPZV2.js";
import { z as getTimeFormatStringFromUserTimeFormat } from "./email-manager-em79awUz.js";
import { TRPCError } from "@trpc/server";
import { randomBytes, createHash } from "crypto";
import { i as isSupportedTimeZone } from "./index-sMkzixNw.js";
import { isValidPhoneNumber } from "libphonenumber-js";
const workflowSelect = {
  id: true,
  trigger: true,
  time: true,
  timeUnit: true,
  userId: true,
  teamId: true,
  name: true,
  steps: {
    select: {
      id: true,
      action: true,
      sendTo: true,
      reminderBody: true,
      emailSubject: true,
      template: true,
      numberVerificationPending: true,
      sender: true,
      includeCalendarEvent: true,
      numberRequired: true,
      verifiedAt: true
    }
  }
};
const getAllWorkflows = async (eventTypeWorkflows, userId, teamId, orgId, workflowsLockedForUser = true) => {
  const allWorkflows = eventTypeWorkflows;
  if (orgId) {
    if (teamId) {
      const orgTeamWorkflowsRel = await prisma.workflowsOnTeams.findMany({
        where: {
          teamId
        },
        select: {
          workflow: {
            select: workflowSelect
          }
        }
      });
      const orgTeamWorkflows = orgTeamWorkflowsRel?.map((workflowRel) => workflowRel.workflow) ?? [];
      allWorkflows.push(...orgTeamWorkflows);
    } else if (userId) {
      const orgUserWorkflowsRel = await prisma.workflowsOnTeams.findMany({
        where: {
          team: {
            members: {
              some: {
                userId,
                accepted: true
              }
            }
          }
        },
        select: {
          workflow: {
            select: workflowSelect
          },
          team: true
        }
      });
      const orgUserWorkflows = orgUserWorkflowsRel.map((workflowRel) => workflowRel.workflow) ?? [];
      allWorkflows.push(...orgUserWorkflows);
    }
    const activeOnAllOrgWorkflows = await prisma.workflow.findMany({
      where: {
        teamId: orgId,
        isActiveOnAll: true
      },
      select: workflowSelect
    });
    allWorkflows.push(...activeOnAllOrgWorkflows);
  }
  if (teamId) {
    const activeOnAllTeamWorkflows = await prisma.workflow.findMany({
      where: {
        teamId,
        isActiveOnAll: true
      },
      select: workflowSelect
    });
    allWorkflows.push(...activeOnAllTeamWorkflows);
  }
  if ((!teamId || !workflowsLockedForUser) && userId) {
    const activeOnAllUserWorkflows = await prisma.workflow.findMany({
      where: {
        userId,
        teamId: null,
        isActiveOnAll: true
      },
      select: workflowSelect
    });
    allWorkflows.push(...activeOnAllUserWorkflows);
  }
  const seen = /* @__PURE__ */ new Set();
  const workflows = allWorkflows.filter((workflow) => {
    const duplicate = seen.has(workflow.id);
    seen.add(workflow.id);
    return !duplicate;
  });
  return workflows;
};
async function getEventType(eventTypeId) {
  const rawEventType = await prisma.eventType.findUnique({
    where: {
      id: eventTypeId
    },
    include: {
      customInputs: true,
      profile: {
        select: {
          organizationId: true
        }
      },
      workflows: {
        select: {
          workflow: {
            select: workflowSelect
          }
        }
      }
    }
  });
  if (!rawEventType) {
    throw new Error(`EventType:${eventTypeId} not found`);
  }
  const { profile, ...restEventType } = rawEventType;
  const isOrgTeamEvent = !!rawEventType?.teamId && !!profile?.organizationId;
  const eventType = {
    ...restEventType,
    bookingFields: getBookingFieldsWithSystemFields({ ...restEventType, isOrgTeamEvent })
  };
  return eventType;
}
async function upsertBookingField(fieldToAdd, source, eventTypeId) {
  const eventType = await getEventType(eventTypeId);
  let fieldFound = false;
  const newFields = eventType.bookingFields.map((f) => {
    if (f.name === fieldToAdd.name) {
      fieldFound = true;
      const currentSources = f.sources ? f.sources : [];
      let sourceFound = false;
      let newSources = currentSources.map((s) => {
        if (s.id !== source.id) {
          return s;
        }
        sourceFound = true;
        return {
          ...s,
          ...source
        };
      });
      if (!sourceFound) {
        newSources = [...newSources, source];
      }
      const newField = {
        ...f,
        // If any source requires the field, mark the field required
        required: newSources.some((s) => s.fieldRequired),
        sources: newSources
      };
      return newField;
    }
    return f;
  });
  if (!fieldFound) {
    newFields.push({
      ...fieldToAdd,
      required: source.fieldRequired,
      sources: [source]
    });
  }
  await prisma.eventType.update({
    where: {
      id: eventTypeId
    },
    data: {
      bookingFields: newFields
    }
  });
}
async function removeBookingField(fieldToRemove, source, eventTypeId) {
  const eventType = await getEventType(eventTypeId);
  const newFields = eventType.bookingFields.map((f) => {
    if (f.name === fieldToRemove.name) {
      const currentSources = f.sources ? f.sources : [];
      if (!currentSources.find((s) => s.id === source.id)) {
        return f;
      }
      const newSources = currentSources.filter((s) => s.id !== source.id);
      const newField = {
        ...f,
        required: newSources.some((s) => s.fieldRequired),
        sources: newSources
      };
      if (newField.sources.length === 0) {
        return null;
      }
      return newField;
    }
    return f;
  }).filter((f) => !!f);
  await prisma.eventType.update({
    where: {
      id: eventTypeId
    },
    data: {
      bookingFields: newFields
    }
  });
}
var Resource = /* @__PURE__ */ ((Resource2) => {
  Resource2["All"] = "*";
  Resource2["EventType"] = "eventType";
  Resource2["Team"] = "team";
  Resource2["Organization"] = "organization";
  Resource2["Attributes"] = "organization.attributes";
  Resource2["Booking"] = "booking";
  Resource2["Insights"] = "insights";
  Resource2["Role"] = "role";
  Resource2["RoutingForm"] = "routingForm";
  Resource2["Workflow"] = "workflow";
  return Resource2;
})(Resource || {});
var CrudAction = /* @__PURE__ */ ((CrudAction2) => {
  CrudAction2["All"] = "*";
  CrudAction2["Create"] = "create";
  CrudAction2["Read"] = "read";
  CrudAction2["Update"] = "update";
  CrudAction2["Delete"] = "delete";
  return CrudAction2;
})(CrudAction || {});
var CustomAction = /* @__PURE__ */ ((CustomAction2) => {
  CustomAction2["Invite"] = "invite";
  CustomAction2["Remove"] = "remove";
  CustomAction2["ChangeMemberRole"] = "changeMemberRole";
  CustomAction2["ListMembers"] = "listMembers";
  CustomAction2["ManageBilling"] = "manageBilling";
  CustomAction2["ReadTeamBookings"] = "readTeamBookings";
  CustomAction2["ReadOrgBookings"] = "readOrgBookings";
  CustomAction2["ReadRecordings"] = "readRecordings";
  CustomAction2["Impersonate"] = "impersonate";
  return CustomAction2;
})(CustomAction || {});
const parsePermissionString = (permission) => {
  const lastDotIndex = permission.lastIndexOf(".");
  const resource = permission.substring(0, lastDotIndex);
  const action = permission.substring(lastDotIndex + 1);
  return { resource, action };
};
const filterResourceConfig = (config) => {
  const { _resource, ...rest } = config;
  return rest;
};
const PERMISSION_REGISTRY = {
  [
    "*"
    /* All */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_all"
    },
    [
      "*"
      /* All */
    ]: {
      description: "All actions on all resources",
      category: "system",
      i18nKey: "pbac_resource_all",
      descriptionI18nKey: "pbac_desc_all_actions_all_resources",
      scope: [
        "organization"
        /* Organization */
      ]
      // Only organizations should have "All" permissions
    }
  },
  [
    "role"
    /* Role */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_role"
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create roles",
      category: "role",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_roles",
      dependsOn: ["role.read"]
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View roles",
      category: "role",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_roles"
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update roles",
      category: "role",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_roles",
      dependsOn: ["role.read"]
    },
    [
      "delete"
      /* Delete */
    ]: {
      description: "Delete roles",
      category: "role",
      i18nKey: "pbac_action_delete",
      descriptionI18nKey: "pbac_desc_delete_roles",
      dependsOn: ["role.read"]
    }
  },
  [
    "eventType"
    /* EventType */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_event_type"
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create event types",
      category: "event",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_event_types",
      dependsOn: ["eventType.read"]
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View event types",
      category: "event",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_event_types"
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update event types",
      category: "event",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_event_types",
      dependsOn: ["eventType.read"]
    },
    [
      "delete"
      /* Delete */
    ]: {
      description: "Delete event types",
      category: "event",
      i18nKey: "pbac_action_delete",
      descriptionI18nKey: "pbac_desc_delete_event_types",
      dependsOn: ["eventType.read"]
    }
  },
  [
    "team"
    /* Team */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_team"
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create teams",
      category: "team",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_teams",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["team.read"]
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View team details",
      category: "team",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_team_details"
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update settings",
      category: "team",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_team_settings",
      dependsOn: ["team.read"]
    },
    [
      "delete"
      /* Delete */
    ]: {
      description: "Delete team",
      category: "team",
      i18nKey: "pbac_action_delete",
      descriptionI18nKey: "pbac_desc_delete_team",
      dependsOn: ["team.read"]
    },
    [
      "invite"
      /* Invite */
    ]: {
      description: "Invite team members",
      category: "team",
      i18nKey: "pbac_action_invite",
      descriptionI18nKey: "pbac_desc_invite_team_members",
      dependsOn: ["team.read", "team.listMembers"]
    },
    [
      "remove"
      /* Remove */
    ]: {
      description: "Remove team members",
      category: "team",
      i18nKey: "pbac_action_remove",
      descriptionI18nKey: "pbac_desc_remove_team_members",
      dependsOn: ["team.read", "team.listMembers"]
    },
    [
      "listMembers"
      /* ListMembers */
    ]: {
      description: "List team members",
      category: "team",
      i18nKey: "pbac_action_list_members",
      descriptionI18nKey: "pbac_desc_list_team_members"
    },
    [
      "changeMemberRole"
      /* ChangeMemberRole */
    ]: {
      description: "Change role of team members",
      category: "team",
      i18nKey: "pbac_action_change_member_role",
      descriptionI18nKey: "pbac_desc_change_team_member_role",
      dependsOn: ["team.read", "team.listMembers"]
    },
    [
      "impersonate"
      /* Impersonate */
    ]: {
      description: "Impersonate team members",
      category: "team",
      i18nKey: "pbac_action_impersonate",
      descriptionI18nKey: "pbac_desc_impersonate_team_members",
      dependsOn: ["team.read", "team.listMembers"]
    }
  },
  [
    "organization"
    /* Organization */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_organization"
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create organization",
      category: "org",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_organization",
      scope: [
        "organization"
        /* Organization */
      ]
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View organization details",
      category: "org",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_organization_details",
      scope: [
        "organization"
        /* Organization */
      ]
    },
    [
      "listMembers"
      /* ListMembers */
    ]: {
      description: "List organization members",
      category: "org",
      i18nKey: "pbac_action_list_members",
      descriptionI18nKey: "pbac_desc_list_organization_members",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["organization.read"]
    },
    [
      "invite"
      /* Invite */
    ]: {
      description: "Invite organization members",
      category: "org",
      i18nKey: "pbac_action_invite",
      descriptionI18nKey: "pbac_desc_invite_organization_members",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["organization.listMembers"]
    },
    [
      "remove"
      /* Remove */
    ]: {
      description: "Remove organization members",
      category: "org",
      i18nKey: "pbac_action_remove",
      descriptionI18nKey: "pbac_desc_remove_organization_members",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["organization.listMembers"]
    },
    [
      "manageBilling"
      /* ManageBilling */
    ]: {
      description: "Manage organization billing",
      category: "org",
      i18nKey: "pbac_action_manage_billing",
      descriptionI18nKey: "pbac_desc_manage_organization_billing",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["organization.read"]
    },
    [
      "changeMemberRole"
      /* ChangeMemberRole */
    ]: {
      description: "Change role of team members",
      category: "org",
      i18nKey: "pbac_action_change_member_role",
      descriptionI18nKey: "pbac_desc_change_organization_member_role",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["organization.listMembers", "role.read"]
    },
    [
      "impersonate"
      /* Impersonate */
    ]: {
      description: "Impersonate organization members",
      category: "org",
      i18nKey: "pbac_action_impersonate",
      descriptionI18nKey: "pbac_desc_impersonate_organization_members",
      scope: [
        "organization"
        /* Organization */
      ]
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Edit organization settings",
      category: "org",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_edit_organization_settings",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["organization.read"]
    }
  },
  [
    "booking"
    /* Booking */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_booking"
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View bookings",
      category: "booking",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_bookings"
    },
    [
      "readTeamBookings"
      /* ReadTeamBookings */
    ]: {
      description: "View team bookings",
      category: "booking",
      i18nKey: "pbac_action_read_team_bookings",
      descriptionI18nKey: "pbac_desc_view_team_bookings",
      scope: [
        "team"
        /* Team */
      ],
      dependsOn: ["booking.read"]
    },
    [
      "readOrgBookings"
      /* ReadOrgBookings */
    ]: {
      description: "View organization bookings",
      category: "booking",
      i18nKey: "pbac_action_read_org_bookings",
      descriptionI18nKey: "pbac_desc_view_organization_bookings",
      scope: [
        "organization"
        /* Organization */
      ],
      dependsOn: ["booking.read"]
    },
    [
      "readRecordings"
      /* ReadRecordings */
    ]: {
      description: "View booking recordings",
      category: "booking",
      i18nKey: "pbac_action_read_recordings",
      descriptionI18nKey: "pbac_desc_view_booking_recordings",
      dependsOn: ["booking.read"]
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update bookings",
      category: "booking",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_bookings",
      dependsOn: ["booking.read"]
    }
  },
  [
    "insights"
    /* Insights */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_insights"
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View team insights and analytics",
      category: "insights",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_team_insights"
    }
  },
  [
    "workflow"
    /* Workflow */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_workflow"
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create workflows",
      category: "workflow",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_workflows",
      dependsOn: ["workflow.read"]
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View workflows",
      category: "workflow",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_workflows"
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update workflows",
      category: "workflow",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_workflows",
      dependsOn: ["workflow.read"]
    },
    [
      "delete"
      /* Delete */
    ]: {
      description: "Delete workflows",
      category: "workflow",
      i18nKey: "pbac_action_delete",
      descriptionI18nKey: "pbac_desc_delete_workflows",
      dependsOn: ["workflow.read"]
    }
  },
  [
    "organization.attributes"
    /* Attributes */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_attributes"
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View organization attributes",
      category: "attributes",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_organization_attributes"
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update organization attributes",
      category: "attributes",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_organization_attributes",
      dependsOn: ["organization.attributes.read"]
    },
    [
      "delete"
      /* Delete */
    ]: {
      description: "Delete organization attributes",
      category: "attributes",
      i18nKey: "pbac_action_delete",
      descriptionI18nKey: "pbac_desc_delete_organization_attributes",
      dependsOn: ["organization.attributes.read"]
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create organization attributes",
      category: "attributes",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_organization_attributes",
      dependsOn: ["organization.attributes.read"]
    }
  },
  [
    "routingForm"
    /* RoutingForm */
  ]: {
    _resource: {
      i18nKey: "pbac_resource_routing_form"
    },
    [
      "create"
      /* Create */
    ]: {
      description: "Create routing forms",
      category: "routing",
      i18nKey: "pbac_action_create",
      descriptionI18nKey: "pbac_desc_create_routing_forms",
      dependsOn: ["routingForm.read"]
    },
    [
      "read"
      /* Read */
    ]: {
      description: "View routing forms",
      category: "routing",
      i18nKey: "pbac_action_read",
      descriptionI18nKey: "pbac_desc_view_routing_forms"
    },
    [
      "update"
      /* Update */
    ]: {
      description: "Update routing forms",
      category: "routing",
      i18nKey: "pbac_action_update",
      descriptionI18nKey: "pbac_desc_update_routing_forms",
      dependsOn: ["routingForm.read"]
    },
    [
      "delete"
      /* Delete */
    ]: {
      description: "Delete routing forms",
      category: "routing",
      i18nKey: "pbac_action_delete",
      descriptionI18nKey: "pbac_desc_delete_routing_forms",
      dependsOn: ["routingForm.read"]
    }
  }
};
class PermissionMapper {
  static toDomain(dbPermissions) {
    return dbPermissions.filter(
      (membership) => membership.teamId != null && membership.role?.id != null && membership.role.permissions
    ).map((membership) => ({
      teamId: membership.teamId,
      roleId: membership.role.id,
      permissions: membership.role.permissions.filter(
        (p) => typeof p.resource === "string" && typeof p.action === "string" && p.resource !== null && p.action !== null
      ).map((p) => ({
        resource: p.resource,
        action: p.action
      }))
    }));
  }
  static toPermissionString(permission) {
    return `${permission.resource}.${permission.action}`;
  }
  static fromPermissionString(permissionString) {
    if (!permissionString || typeof permissionString !== "string" || !permissionString.includes(".")) {
      throw new Error(`Invalid permission format: ${permissionString}`);
    }
    const lastDotIndex = permissionString.lastIndexOf(".");
    const resource = permissionString.substring(0, lastDotIndex);
    const action = permissionString.substring(lastDotIndex + 1);
    if (!resource || !action) {
      throw new Error(`Invalid permission format: ${permissionString}`);
    }
    return {
      resource,
      action
    };
  }
  static toActionMap(permissions, resource) {
    const actionMap = {};
    Object.values(CrudAction).forEach((action) => {
      if (action !== CrudAction.All && this.isActionAvailableForResource(resource, action)) {
        actionMap[action] = false;
      }
    });
    Object.values(CustomAction).forEach((action) => {
      if (this.isActionAvailableForResource(resource, action)) {
        actionMap[action] = false;
      }
    });
    permissions.forEach((permString) => {
      try {
        if (permString === `${Resource.All}.${CrudAction.All}`) {
          Object.keys(actionMap).forEach((key) => {
            actionMap[key] = true;
          });
          return;
        }
        const { action, resource: permResource } = this.fromPermissionString(permString);
        if (permResource === resource || permResource === Resource.All) {
          if (action === CrudAction.All) {
            Object.keys(actionMap).forEach((key) => {
              actionMap[key] = true;
            });
          } else if (this.isActionAvailableForResource(resource, action)) {
            actionMap[action] = true;
          }
        }
      } catch (error) {
        console.error(`Invalid permission string: ${permString}`);
      }
    });
    return actionMap;
  }
  static isActionAvailableForResource(resource, action) {
    return !!PERMISSION_REGISTRY[resource]?.[action];
  }
}
class PermissionRepository {
  constructor(client = prisma) {
    this.client = client;
  }
  async getUserMemberships(userId) {
    const memberships = await this.client.membership.findMany({
      where: { userId },
      include: {
        customRole: {
          include: {
            permissions: true
          }
        }
      }
    });
    const mapped = memberships.map((membership) => ({
      teamId: membership.teamId,
      role: membership.customRole ? {
        id: membership.customRole.id,
        permissions: membership.customRole.permissions
      } : null
    }));
    return PermissionMapper.toDomain(mapped);
  }
  async getMembershipByMembershipId(membershipId) {
    return this.client.membership.findUnique({
      where: { id: membershipId },
      select: {
        id: true,
        teamId: true,
        userId: true,
        customRoleId: true,
        team: {
          select: {
            parentId: true
          }
        }
      }
    });
  }
  async getMembershipByUserAndTeam(userId, teamId) {
    return this.client.membership.findFirst({
      where: {
        userId,
        teamId
      },
      select: {
        id: true,
        teamId: true,
        userId: true,
        customRoleId: true,
        team: {
          select: {
            parentId: true
          }
        }
      }
    });
  }
  async getOrgMembership(userId, orgId) {
    return this.client.membership.findFirst({
      where: {
        userId,
        teamId: orgId
      },
      select: {
        id: true,
        teamId: true,
        userId: true,
        customRoleId: true
      }
    });
  }
  async checkRolePermission(roleId, permission) {
    const { resource, action } = parsePermissionString(permission);
    const hasPermission = await this.client.rolePermission.findFirst({
      where: {
        roleId,
        OR: [
          { resource: "*", action: "*" },
          { resource: "*", action },
          { resource, action: "*" },
          { resource, action }
        ]
      }
    });
    return !!hasPermission;
  }
  async checkRolePermissions(roleId, permissions) {
    if (permissions.length === 0) {
      return false;
    }
    const permissionPairs = permissions.map((p) => {
      const { resource, action } = parsePermissionString(p);
      return { resource, action };
    });
    const resourceActions = permissionPairs.map((p) => [p.resource, p.action]);
    const resources = permissionPairs.map((p) => p.resource);
    const actions = permissionPairs.map((p) => p.action);
    const matchingPermissions = await this.client.$queryRaw`
      WITH permission_checks AS (
        -- Universal permission (*,*)
        SELECT 1 as match FROM "RolePermission"
        WHERE "roleId" = ${roleId} AND "resource" = '*' AND "action" = '*'

        UNION ALL

        -- Wildcard resource with specific actions
        SELECT 1 as match FROM "RolePermission"
        WHERE "roleId" = ${roleId} AND "resource" = '*' AND "action" = ANY(${actions})

        UNION ALL

        -- Specific resources with wildcard action
        SELECT 1 as match FROM "RolePermission"
        WHERE "roleId" = ${roleId} AND "action" = '*' AND "resource" = ANY(${resources})

        UNION ALL

        -- Exact resource-action pairs
        SELECT 1 as match FROM "RolePermission"
        WHERE "roleId" = ${roleId} AND ("resource", "action") = ANY(${resourceActions})
      )
      SELECT COUNT(*) as count FROM permission_checks
    `;
    return Number(matchingPermissions[0].count) >= permissions.length;
  }
  async getResourcePermissions(userId, teamId, resource) {
    const membership = await this.client.membership.findFirst({
      where: {
        userId,
        teamId
      },
      select: {
        customRoleId: true
      }
    });
    if (!membership?.customRoleId)
      return [];
    const teamPermissions = await this.client.rolePermission.findMany({
      where: {
        roleId: membership.customRoleId,
        OR: [{ resource }, { resource: Resource.All }]
      },
      select: {
        action: true,
        resource: true
      }
    });
    return teamPermissions.map((p) => p.action);
  }
  async getResourcePermissionsByRoleId(roleId, resource) {
    const permissions = await this.client.rolePermission.findMany({
      where: {
        roleId,
        OR: [{ resource }, { resource: Resource.All }]
      },
      select: {
        action: true,
        resource: true
      }
    });
    return permissions.map((p) => p.action);
  }
  async getTeamIdsWithPermission(userId, permission) {
    return this.getTeamIdsWithPermissions(userId, [permission]);
  }
  async getTeamIdsWithPermissions(userId, permissions) {
    if (permissions.length === 0) {
      return [];
    }
    const permissionPairs = permissions.map((p) => {
      const { resource, action } = parsePermissionString(p);
      return { resource, action };
    });
    const teamsWithPermission = await this.client.$queryRaw`
      SELECT DISTINCT m."teamId"
      FROM "Membership" m
      INNER JOIN "Role" r ON m."customRoleId" = r.id
      WHERE m."userId" = ${userId}
        AND m."accepted" = true
        AND m."customRoleId" IS NOT NULL
        AND (
          SELECT COUNT(*)
          FROM jsonb_array_elements(${JSON.stringify(permissionPairs)}::jsonb) AS required_perm(perm)
          WHERE EXISTS (
            SELECT 1
            FROM "RolePermission" rp
            WHERE rp."roleId" = r.id
              AND (
                (rp."resource" = '*' AND rp."action" = '*') OR
                (rp."resource" = '*' AND rp."action" = required_perm.perm->>'action') OR
                (rp."resource" = required_perm.perm->>'resource' AND rp."action" = '*') OR
                (rp."resource" = required_perm.perm->>'resource' AND rp."action" = required_perm.perm->>'action')
              )
          )
        ) = ${permissions.length}
    `;
    return teamsWithPermission.map((team) => team.teamId);
  }
}
const isPermissionDetails = (obj) => {
  return obj && "description" in obj && "category" in obj && "i18nKey" in obj && "descriptionI18nKey" in obj;
};
class PermissionService {
  validatePermission(permission) {
    try {
      const permissionObj = PermissionMapper.fromPermissionString(permission);
      const registryEntry = PERMISSION_REGISTRY[permissionObj.resource];
      const actionEntry = registryEntry?.[permissionObj.action];
      const isValid = !!actionEntry;
      return {
        isValid,
        error: isValid ? null : `Invalid permission: ${permission}`
      };
    } catch (error) {
      console.debug(`[DEBUG] Error validating permission ${permission}:`, error);
      if (error instanceof Error) {
        return {
          isValid: false,
          error: error.message
        };
      }
      return {
        isValid: false,
        error: `Invalid permission format: ${permission}`
      };
    }
  }
  validatePermissions(permissions) {
    for (const permission of permissions) {
      const result = this.validatePermission(permission);
      if (!result.isValid) {
        return result;
      }
    }
    return { isValid: true, error: null };
  }
  permissionMatches(pattern, permission) {
    if (pattern.resource === "*" && pattern.action === "*")
      return true;
    const resourceMatches = pattern.resource === "*" || pattern.resource === permission.resource;
    const actionMatches = pattern.action === "*" || pattern.action === permission.action;
    return resourceMatches && actionMatches;
  }
  getAllPermissions() {
    const permissions = [];
    Object.entries(PERMISSION_REGISTRY).forEach(([resource, actions]) => {
      const filteredActions = filterResourceConfig(actions);
      Object.entries(filteredActions).forEach(([action, details]) => {
        if (details && isPermissionDetails(details)) {
          permissions.push({
            resource,
            action,
            description: details?.description,
            category: details?.category
          });
        }
      });
    });
    return permissions;
  }
  getPermissionsByResource(resource) {
    const resourcePermissions = PERMISSION_REGISTRY[resource];
    if (!resourcePermissions)
      return [];
    const filteredPermissions = filterResourceConfig(resourcePermissions);
    return Object.entries(filteredPermissions).filter(([_, details]) => details !== void 0 && isPermissionDetails(details)).map(([action, details]) => ({
      resource,
      action,
      description: details?.description,
      category: details?.category
    }));
  }
  getPermissionsByCategory(category) {
    return this.getAllPermissions().filter((p) => p.category === category);
  }
  getPermissionCategories() {
    return Array.from(
      new Set(
        this.getAllPermissions().map((p) => p.category).filter((category) => category !== void 0)
      )
    );
  }
  getPermissionsByAction(action) {
    return this.getAllPermissions().filter((p) => p.action === action);
  }
}
const DOGFOOD_PBAC_INTERNALLY = true;
class PermissionCheckService {
  constructor(repository = new PermissionRepository(), featuresRepository = new FeaturesRepository(prisma), permissionService = new PermissionService()) {
    this.repository = repository;
    this.PBAC_FEATURE_FLAG = "pbac";
    this.logger = logger.getSubLogger({ prefix: ["PermissionCheckService"] });
    this.featuresRepository = featuresRepository;
    this.permissionService = permissionService;
  }
  async getUserPermissions(userId) {
    const memberships = await this.repository.getUserMemberships(userId);
    return memberships;
  }
  /**
   * Gets all permissions for a specific resource in a team context
   * @warning: this approach of fetching permssions per resource does not account for fall back roles. This should be used in places where you know PBAC is enabled and has been rolled out.
   */
  async getResourcePermissions({
    userId,
    teamId,
    resource
  }) {
    try {
      const isPBACEnabled = await this.featuresRepository.checkIfTeamHasFeature(
        teamId,
        this.PBAC_FEATURE_FLAG
      );
      if (!isPBACEnabled) {
        return [];
      }
      const { membership, orgMembership } = await this.getMembership({ userId, teamId });
      const actions = /* @__PURE__ */ new Set();
      if (membership?.customRoleId) {
        const teamActions = await this.repository.getResourcePermissionsByRoleId(
          membership.customRoleId,
          resource
        );
        teamActions.forEach((action) => actions.add(action));
      }
      if (membership?.team?.parentId && orgMembership?.customRoleId) {
        const orgActions = await this.repository.getResourcePermissionsByRoleId(
          orgMembership.customRoleId,
          resource
        );
        orgActions.forEach((action) => actions.add(action));
      }
      return Array.from(actions).map((action) => PermissionMapper.toPermissionString({ resource, action }));
    } catch (error) {
      this.logger.error(error);
      return [];
    }
  }
  /**
   * Checks if a user has a specific permission in a team context
   */
  async checkPermission({
    userId,
    teamId,
    permission,
    fallbackRoles
  }) {
    try {
      const validationResult = this.permissionService.validatePermission(permission);
      if (!validationResult.isValid) {
        this.logger.error(validationResult.error);
        return false;
      }
      const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({
        userId,
        teamId
      });
      if (!membership)
        return false;
      const isPBACEnabled = await this.featuresRepository.checkIfTeamHasFeature(
        teamId,
        this.PBAC_FEATURE_FLAG
      );
      if (isPBACEnabled) {
        if (!membership.customRoleId) {
          this.logger.info(`PBAC is enabled for ${teamId} but no custom role is set on membership relation`);
          return false;
        }
        const hasPbacPermission = await this.hasPermission({ membershipId: membership.id }, permission);
        if (DOGFOOD_PBAC_INTERNALLY && !hasPbacPermission) {
          return this.dogfoodFallback({
            userId,
            teamId,
            membershipId: membership.id,
            permissions: [permission],
            hasPbacPermission,
            fallbackRoles,
            membershipRole: membership.role
          });
        }
        return hasPbacPermission;
      }
      return this.checkFallbackRoles(membership.role, fallbackRoles);
    } catch (error) {
      this.logger.error(error);
      return false;
    }
  }
  /**
   * Checks if a user has all specified permissions in a team context
   */
  async checkPermissions({
    userId,
    teamId,
    permissions,
    fallbackRoles
  }) {
    try {
      const validationResult = this.permissionService.validatePermissions(permissions);
      if (!validationResult.isValid) {
        this.logger.error(validationResult.error);
        return false;
      }
      const membership = await MembershipRepository.findUniqueByUserIdAndTeamId({
        userId,
        teamId
      });
      if (!membership)
        return false;
      const isPBACEnabled = await this.featuresRepository.checkIfTeamHasFeature(
        teamId,
        this.PBAC_FEATURE_FLAG
      );
      if (isPBACEnabled) {
        if (!membership.customRoleId) {
          this.logger.info(`PBAC is enabled for ${teamId} but no custom role is set on membership relation`);
          return false;
        }
        const hasPbacPermission = await this.hasPermissions({ membershipId: membership.id }, permissions);
        if (DOGFOOD_PBAC_INTERNALLY && !hasPbacPermission) {
          return this.dogfoodFallback({
            userId,
            teamId,
            membershipId: membership.id,
            permissions,
            hasPbacPermission,
            fallbackRoles,
            membershipRole: membership.role
          });
        }
        return hasPbacPermission;
      }
      return this.checkFallbackRoles(membership.role, fallbackRoles);
    } catch (error) {
      this.logger.error(error);
      return false;
    }
  }
  /**
   * Internal method to check permissions for a specific role
   */
  async hasPermission(query, permission) {
    const { membership, orgMembership } = await this.getMembership(query);
    if (membership?.customRoleId) {
      const hasTeamPermission = await this.repository.checkRolePermission(
        membership.customRoleId,
        permission
      );
      if (hasTeamPermission)
        return true;
    }
    if (orgMembership?.customRoleId) {
      return this.repository.checkRolePermission(orgMembership.customRoleId, permission);
    }
    return false;
  }
  /**
   * Internal method to check multiple permissions for a specific role
   */
  async hasPermissions(query, permissions) {
    const { membership, orgMembership } = await this.getMembership(query);
    if (membership?.customRoleId) {
      const hasTeamPermissions = await this.repository.checkRolePermissions(
        membership.customRoleId,
        permissions
      );
      if (hasTeamPermissions)
        return true;
    }
    if (orgMembership?.customRoleId) {
      return this.repository.checkRolePermissions(orgMembership.customRoleId, permissions);
    }
    return false;
  }
  async getMembership(query) {
    let membership = null;
    let orgMembership = null;
    if (query.membershipId) {
      membership = await this.repository.getMembershipByMembershipId(query.membershipId);
    } else if (query.userId && query.teamId) {
      membership = await this.repository.getMembershipByUserAndTeam(query.userId, query.teamId);
    }
    if (membership?.team.parentId) {
      orgMembership = await this.repository.getOrgMembership(membership.userId, membership.team.parentId);
    }
    return { membership, orgMembership };
  }
  checkFallbackRoles(userRole, allowedRoles) {
    return allowedRoles.includes(userRole);
  }
  /**
   * Internal dogfooding fallback for PBAC permissions
   *
   * This method is used internally at Cal.com to help us transition to PBAC.
   * When PBAC is enabled but a user doesn't have the necessary permission strings,
   * we fall back to checking their legacy fallback roles to avoid breaking existing workflows.
   *
   * An alert is logged to Axiom when this fallback occurs so we can identify and fix
   * missing permissions in our PBAC configuration.
   *
   * @private
   * @param params - Object containing userId, teamId, membershipId, permissions, hasPbacPermission, fallbackRoles, and membershipRole
   * @returns boolean - Whether the user has permission via fallback roles
   */
  dogfoodFallback(params) {
    const { userId, teamId, membershipId, permissions, hasPbacPermission, fallbackRoles, membershipRole } = params;
    const debugInfo = {
      userId,
      teamId,
      membershipId,
      permissions,
      hasPbacPermission,
      fallbackRoles
    };
    this.logger.warn(
      `PBAC INTERNAL - Failed but user doesnt have permission string to carry out this action. Falling back to fallback roles. 
 JSON${JSON.stringify(
        debugInfo,
        null,
        2
      )}`
    );
    return this.checkFallbackRoles(membershipRole, fallbackRoles);
  }
  /**
   * Gets all team IDs where the user has a specific permission
   */
  async getTeamIdsWithPermission(userId, permission) {
    try {
      const validationResult = this.permissionService.validatePermission(permission);
      if (!validationResult.isValid) {
        this.logger.error(validationResult.error);
        return [];
      }
      return await this.repository.getTeamIdsWithPermission(userId, permission);
    } catch (error) {
      this.logger.error(error);
      return [];
    }
  }
  /**
   * Gets all team IDs where the user has all of the specified permissions
   */
  async getTeamIdsWithPermissions(userId, permissions) {
    try {
      const validationResult = this.permissionService.validatePermissions(permissions);
      if (!validationResult.isValid) {
        this.logger.error(validationResult.error);
        return [];
      }
      return await this.repository.getTeamIdsWithPermissions(userId, permissions);
    } catch (error) {
      this.logger.error(error);
      return [];
    }
  }
}
async function getTeamIdFromEventType({
  eventType
}) {
  if (!eventType) {
    return null;
  }
  if (eventType?.team?.id) {
    return eventType.team.id;
  }
  if (eventType?.parentId) {
    const managedEvent = await prisma.eventType.findUnique({
      where: {
        id: eventType.parentId
      },
      select: {
        teamId: true
      }
    });
    return managedEvent?.teamId;
  }
}
z.object({
  id: z.number()
});
const deleteScheduledWhatsappReminder = deleteScheduledSMSReminder;
const { include: includedFields } = {
  include: {
    activeOn: {
      select: {
        eventType: {
          select: {
            id: true,
            title: true,
            parentId: true,
            _count: {
              select: {
                children: true
              }
            }
          }
        }
      }
    },
    activeOnTeams: {
      select: {
        team: {
          select: {
            id: true,
            name: true
          }
        }
      }
    },
    steps: true,
    team: {
      select: {
        id: true,
        slug: true,
        name: true,
        members: true,
        logoUrl: true,
        isOrganization: true
      }
    }
  }
};
class WorkflowRepository {
  static {
    this.log = logger.getSubLogger({ prefix: ["workflow"] });
  }
  static async getById({ id }) {
    return await prisma.workflow.findUnique({
      where: {
        id
      },
      select: {
        id: true,
        name: true,
        userId: true,
        teamId: true,
        isActiveOnAll: true,
        team: {
          select: {
            id: true,
            slug: true,
            members: true,
            name: true,
            isOrganization: true
          }
        },
        time: true,
        timeUnit: true,
        activeOn: {
          select: {
            eventType: true
          }
        },
        activeOnTeams: {
          select: {
            team: true
          }
        },
        trigger: true,
        steps: {
          orderBy: {
            stepNumber: "asc"
          }
        }
      }
    });
  }
  static async getVerifiedNumbers({
    userId,
    teamId
  }) {
    if (!userId) {
      throw new Error("User Id not found");
    }
    const verifiedNumbers = await prisma.verifiedNumber.findMany({
      where: {
        OR: [{ userId }, { teamId }]
      }
    });
    return verifiedNumbers;
  }
  static async getVerifiedEmails({
    userEmail,
    userId,
    teamId
  }) {
    if (!userId) {
      throw new Error("User Id not found");
    }
    if (!userEmail) {
      throw new Error("User email not found");
    }
    let verifiedEmails = [userEmail];
    const secondaryEmails = await prisma.secondaryEmail.findMany({
      where: {
        userId,
        emailVerified: {
          not: null
        }
      }
    });
    verifiedEmails = verifiedEmails.concat(secondaryEmails.map((secondaryEmail) => secondaryEmail.email));
    if (teamId) {
      const teamMembers = await prisma.user.findMany({
        where: {
          teams: {
            some: {
              teamId
            }
          }
        },
        select: {
          id: true,
          email: true,
          secondaryEmails: {
            where: {
              emailVerified: {
                not: null
              }
            },
            select: {
              email: true
            }
          }
        }
      });
      if (!teamMembers.length) {
        throw new Error("Team not found");
      }
      const isTeamMember = teamMembers.some((member) => member.id === userId);
      if (!isTeamMember) {
        throw new Error("You are not a member of this team");
      }
      teamMembers.forEach((member) => {
        if (member.id === userId) {
          return;
        }
        verifiedEmails.push(member.email);
        member.secondaryEmails.forEach((secondaryEmail) => {
          verifiedEmails.push(secondaryEmail.email);
        });
      });
    }
    const emails = (await prisma.verifiedEmail.findMany({
      where: {
        OR: [{ userId }, { teamId }]
      }
    })).map((verifiedEmail) => verifiedEmail.email);
    verifiedEmails = verifiedEmails.concat(emails);
    return verifiedEmails;
  }
  static async getFilteredList({ userId, input }) {
    const filters = input?.filters;
    const filtered = filters && hasFilter(filters);
    const allWorkflows = await prisma.workflow.findMany({
      where: {
        OR: [
          {
            userId
          },
          {
            team: {
              members: {
                some: {
                  userId,
                  accepted: true
                }
              }
            }
          }
        ]
      },
      include: includedFields,
      orderBy: [
        {
          position: "desc"
        },
        {
          id: "desc"
        }
      ]
    });
    if (!filtered) {
      const workflowsWithReadOnly = allWorkflows.map((workflow) => {
        const readOnly = !!workflow.team?.members?.find(
          (member) => member.userId === userId && member.role === MembershipRole.MEMBER
        );
        return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
      });
      return {
        filtered: workflowsWithReadOnly,
        totalCount: allWorkflows.length
      };
    }
    const where = {
      OR: []
    };
    if (filtered) {
      if (!!filters.teamIds) {
        where.OR.push({
          team: {
            id: {
              in: filters.teamIds ?? []
            },
            members: {
              some: {
                userId,
                accepted: true
              }
            }
          }
        });
      }
      if (!!filters.userIds) {
        where.OR.push({
          userId: {
            in: filters.userIds
          },
          teamId: null
        });
      }
      const filteredWorkflows = await prisma.workflow.findMany({
        where,
        include: includedFields,
        orderBy: {
          id: "desc"
        }
      });
      const workflowsWithReadOnly = filteredWorkflows.map((workflow) => {
        const readOnly = !!workflow.team?.members?.find(
          (member) => member.userId === userId && member.role === MembershipRole.MEMBER
        );
        return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
      });
      return {
        filtered: workflowsWithReadOnly,
        totalCount: allWorkflows.length
      };
    }
  }
  static async getRemindersFromRemovedTeams(removedTeams, workflowSteps, activeOn) {
    const remindersToDeletePromise = [];
    removedTeams.forEach((teamId) => {
      const reminderToDelete = prisma.workflowReminder.findMany({
        where: {
          OR: [
            {
              //team event types + children managed event types
              booking: {
                eventType: {
                  OR: [{ teamId }, { teamId: null, parent: { teamId } }]
                }
              }
            },
            {
              // user bookings
              booking: {
                user: {
                  AND: [
                    // user is part of team that got removed
                    {
                      teams: {
                        some: {
                          teamId
                        }
                      }
                    },
                    // and user is not part of any team were the workflow is still active on
                    {
                      teams: {
                        none: {
                          teamId: {
                            in: activeOn
                          }
                        }
                      }
                    }
                  ]
                },
                eventType: {
                  teamId: null,
                  parentId: null
                  // children managed event types are handled above with team event types
                }
              }
            }
          ],
          workflowStepId: {
            in: workflowSteps.map((step) => {
              return step.id;
            })
          }
        },
        select: {
          id: true,
          referenceId: true,
          method: true
        }
      });
      remindersToDeletePromise.push(reminderToDelete);
    });
    const remindersToDelete = (await Promise.all(remindersToDeletePromise)).flat();
    return remindersToDelete;
  }
  static async getActiveOnEventTypeIds({
    workflowId,
    userId,
    teamId
  }) {
    const workflow = await prisma.workflow.findFirst({
      where: {
        id: workflowId,
        userId,
        teamId: teamId ?? void 0
      },
      select: {
        activeOn: {
          select: {
            eventTypeId: true
          }
        }
      }
    });
    if (!workflow) {
      throw new HttpError({
        statusCode: 404,
        message: "Workflow not found"
      });
    }
    return workflow.activeOn.map((active) => active.eventTypeId);
  }
  static async deleteAllWorkflowReminders(remindersToDelete) {
    const reminderMethods = {
      [WorkflowMethods.EMAIL]: (id, referenceId) => deleteScheduledEmailReminder(id),
      [WorkflowMethods.SMS]: (id, referenceId) => deleteScheduledSMSReminder(id, referenceId),
      [WorkflowMethods.WHATSAPP]: (id, referenceId) => deleteScheduledWhatsappReminder(id, referenceId),
      [WorkflowMethods.AI_PHONE_CALL]: (id, referenceId) => deleteScheduledAIPhoneCall(id, referenceId)
    };
    if (!remindersToDelete)
      return Promise.resolve();
    const results = await Promise.allSettled(
      remindersToDelete.map((reminder) => {
        return reminderMethods[reminder.method](reminder.id, reminder.referenceId);
      })
    );
    results.forEach((result, index) => {
      if (result.status !== "fulfilled") {
        this.log.error(
          `An error occurred when deleting reminder ${remindersToDelete[index].id}, method: ${remindersToDelete[index].method}`,
          result.reason
        );
      }
    });
  }
}
logger.getSubLogger({ prefix: ["workflow"] });
const bookingSelect = {
  userPrimaryEmail: true,
  startTime: true,
  endTime: true,
  title: true,
  uid: true,
  metadata: true,
  smsReminderNumber: true,
  responses: true,
  attendees: {
    select: {
      name: true,
      email: true,
      timeZone: true,
      locale: true
    }
  },
  eventType: {
    select: {
      slug: true,
      id: true,
      schedulingType: true,
      hideOrganizerEmail: true,
      customReplyToEmail: true,
      hosts: {
        select: {
          user: {
            select: {
              email: true,
              destinationCalendar: {
                select: {
                  primaryEmail: true
                }
              }
            }
          }
        }
      }
    }
  },
  user: {
    select: {
      name: true,
      timeZone: true,
      timeFormat: true,
      locale: true,
      email: true
    }
  }
};
const verifyEmailSender = async (email, userId, teamId) => {
  const verifiedEmail = await prisma.verifiedEmail.findFirst({
    where: {
      email,
      OR: [{ userId }, { teamId }]
    }
  });
  if (verifiedEmail) {
    if (teamId) {
      if (!verifiedEmail.teamId) {
        await prisma.verifiedEmail.update({
          where: {
            id: verifiedEmail.id
          },
          data: {
            teamId
          }
        });
      } else if (verifiedEmail.teamId !== teamId) {
        await prisma.verifiedEmail.create({
          data: {
            email,
            userId,
            teamId
          }
        });
      }
    }
    return;
  }
  const userEmail = await prisma.user.findFirst({
    where: {
      id: userId,
      email
    }
  });
  if (userEmail) {
    await prisma.verifiedEmail.create({
      data: {
        email,
        userId,
        teamId
      }
    });
    return;
  }
  const secondaryEmail = await prisma.secondaryEmail.findFirst({
    where: {
      userId,
      email,
      emailVerified: {
        not: null
      }
    }
  });
  if (secondaryEmail) {
    await prisma.verifiedEmail.create({
      data: {
        email,
        userId,
        teamId
      }
    });
    return;
  }
  if (teamId) {
    const team = await prisma.team.findUnique({
      where: {
        id: teamId
      },
      select: {
        members: {
          include: {
            user: {
              select: {
                id: true,
                email: true,
                secondaryEmails: {
                  select: {
                    email: true,
                    emailVerified: true
                  }
                }
              }
            }
          }
        }
      }
    });
    if (!team) {
      throw new TRPCError({ code: "NOT_FOUND", message: "Team not found" });
    }
    const isTeamMember = team.members.some((member) => member.userId === userId);
    if (!isTeamMember) {
      throw new TRPCError({ code: "FORBIDDEN", message: "You are not a member of this team" });
    }
    let foundTeamMember = team.members.find((member) => member.user.email === email);
    if (!foundTeamMember) {
      foundTeamMember = team.members.find(
        (member) => member.user.secondaryEmails.some(
          (secondary) => secondary.email === email && !!secondary.emailVerified
        )
      );
    }
    if (foundTeamMember) {
      await prisma.verifiedEmail.create({
        data: {
          email,
          userId,
          teamId
        }
      });
      return;
    }
  }
  throw new TRPCError({ code: "NOT_FOUND", message: "Email not verified" });
};
function getSender(step) {
  return isSMSOrWhatsappAction(step.action) ? step.sender || SENDER_ID : step.senderName || SENDER_NAME;
}
async function isAuthorized(workflow, currentUserId, permission = "workflow.read") {
  if (!workflow) {
    return false;
  }
  if (!workflow.teamId) {
    return workflow.userId === currentUserId;
  }
  const permissionService = new PermissionCheckService();
  const fallbackRoles = permission === "workflow.read" ? [MembershipRole.ADMIN, MembershipRole.OWNER, MembershipRole.MEMBER] : [MembershipRole.ADMIN, MembershipRole.OWNER];
  return await permissionService.checkPermission({
    userId: currentUserId,
    teamId: workflow.teamId,
    permission,
    fallbackRoles
  });
}
async function upsertSmsReminderFieldForEventTypes({
  activeOn,
  workflowId,
  isSmsReminderNumberRequired,
  isOrg
}) {
  let allEventTypeIds = activeOn;
  if (isOrg) {
    allEventTypeIds = await getAllUserAndTeamEventTypes(activeOn);
  }
  for (const eventTypeId of allEventTypeIds) {
    await upsertBookingField(
      getSmsReminderNumberField(),
      getSmsReminderNumberSource({
        workflowId,
        isSmsReminderNumberRequired
      }),
      eventTypeId
    );
  }
}
async function removeSmsReminderFieldForEventTypes({
  activeOnToRemove,
  workflowId,
  isOrg,
  activeOn
}) {
  let allEventTypeIds = activeOnToRemove;
  if (isOrg) {
    allEventTypeIds = await getAllUserAndTeamEventTypes(activeOnToRemove, activeOn);
  }
  for (const eventTypeId of allEventTypeIds) {
    await removeSmsReminderFieldForEventType({
      workflowId,
      eventTypeId
    });
  }
}
async function removeSmsReminderFieldForEventType({
  workflowId,
  eventTypeId
}) {
  await removeBookingField(
    {
      name: SMS_REMINDER_NUMBER_FIELD
    },
    {
      id: `${workflowId}`,
      type: "workflow"
    },
    eventTypeId
  );
}
async function upsertAIAgentCallPhoneNumberFieldForEventTypes({
  activeOn,
  workflowId,
  isAIAgentCallPhoneNumberRequired,
  isOrg
}) {
  let allEventTypeIds = activeOn;
  if (isOrg) {
    allEventTypeIds = await getAllUserAndTeamEventTypes(activeOn);
  }
  for (const eventTypeId of allEventTypeIds) {
    await upsertBookingField(
      getAIAgentCallPhoneNumberField(),
      getAIAgentCallPhoneNumberSource({
        workflowId,
        isAIAgentCallPhoneNumberRequired: isAIAgentCallPhoneNumberRequired ?? false
      }),
      eventTypeId
    );
  }
}
async function removeAIAgentCallPhoneNumberFieldForEventTypes({
  activeOnToRemove,
  workflowId,
  isOrg,
  activeOn
}) {
  let allEventTypeIds = activeOnToRemove;
  if (isOrg) {
    allEventTypeIds = await getAllUserAndTeamEventTypes(activeOnToRemove, activeOn);
  }
  for (const eventTypeId of allEventTypeIds) {
    await removeAIAgentCallPhoneNumberFieldForEventType({
      workflowId,
      eventTypeId
    });
  }
}
async function removeAIAgentCallPhoneNumberFieldForEventType({
  workflowId,
  eventTypeId
}) {
  await removeBookingField(
    {
      name: CAL_AI_AGENT_PHONE_NUMBER_FIELD
    },
    {
      id: `${workflowId}`,
      type: "workflow"
    },
    eventTypeId
  );
}
async function getAllUserAndTeamEventTypes(teamIds, notMemberOfTeamId = []) {
  const teamMembersWithEventTypes = await prisma.membership.findMany({
    where: {
      teamId: {
        in: teamIds
      },
      user: {
        teams: {
          none: {
            team: {
              id: {
                in: notMemberOfTeamId ?? []
              }
            }
          }
        }
      }
    },
    select: {
      user: {
        select: {
          eventTypes: {
            select: {
              id: true
            }
          }
        }
      }
    }
  });
  const teamEventTypes = await prisma.eventType.findMany({
    where: {
      teamId: {
        in: teamIds
      }
    }
  });
  const userEventTypes = teamMembersWithEventTypes?.flatMap(
    (membership) => membership.user.eventTypes.map((et) => et.id)
  );
  return teamEventTypes.map((et) => et.id).concat(userEventTypes);
}
async function isAuthorizedToAddActiveOnIds(newActiveIds, isOrg, teamId, userId) {
  for (const id of newActiveIds) {
    if (isOrg) {
      const newTeam = await prisma.team.findUnique({
        where: {
          id
        },
        select: {
          parent: true
        }
      });
      if (newTeam?.parent?.id !== teamId) {
        return false;
      }
    } else {
      const newEventType = await prisma.eventType.findUnique({
        where: {
          id
        },
        include: {
          users: {
            select: {
              id: true
            }
          },
          children: true
        }
      });
      if (newEventType) {
        if (teamId && teamId !== newEventType.teamId) {
          return false;
        }
        if (!teamId && userId && newEventType.userId !== userId && !newEventType?.users.find((eventTypeUser) => eventTypeUser.id === userId)) {
          return false;
        }
      }
    }
  }
  return true;
}
async function deleteRemindersOfActiveOnIds({
  removedActiveOnIds,
  workflowSteps,
  isOrg,
  activeOnIds
}) {
  const remindersToDelete = !isOrg ? await getRemindersFromRemovedEventTypes(removedActiveOnIds, workflowSteps) : await WorkflowRepository.getRemindersFromRemovedTeams(removedActiveOnIds, workflowSteps, activeOnIds);
  await WorkflowRepository.deleteAllWorkflowReminders(remindersToDelete);
}
async function getRemindersFromRemovedEventTypes(removedEventTypes, workflowSteps) {
  const remindersToDeletePromise = [];
  removedEventTypes.forEach((eventTypeId) => {
    const remindersToDelete2 = prisma.workflowReminder.findMany({
      where: {
        booking: {
          eventTypeId
        },
        workflowStepId: {
          in: workflowSteps.map((step) => {
            return step.id;
          })
        }
      },
      select: {
        id: true,
        referenceId: true,
        method: true
      }
    });
    remindersToDeletePromise.push(remindersToDelete2);
  });
  const remindersToDelete = (await Promise.all(remindersToDeletePromise)).flat();
  return remindersToDelete;
}
async function scheduleWorkflowNotifications({
  activeOn,
  isOrg,
  workflowSteps,
  time,
  timeUnit,
  trigger,
  userId,
  teamId,
  alreadyScheduledActiveOnIds
}) {
  const bookingsToScheduleNotifications = await getBookings(activeOn, isOrg, alreadyScheduledActiveOnIds);
  await scheduleBookingReminders(
    bookingsToScheduleNotifications,
    workflowSteps,
    time,
    timeUnit,
    trigger,
    userId,
    teamId,
    isOrg
  );
}
async function getBookings(activeOn, isOrg, alreadyScheduledActiveOnIds = []) {
  if (activeOn.length === 0)
    return [];
  if (isOrg) {
    const bookingsForReminders = await prisma.booking.findMany({
      where: {
        OR: [
          {
            // bookings from team event types + children managed event types
            eventType: {
              OR: [
                {
                  teamId: {
                    in: activeOn
                  }
                },
                {
                  teamId: null,
                  parent: {
                    teamId: {
                      in: activeOn
                    }
                  }
                }
              ]
            }
          },
          {
            // user bookings
            user: {
              teams: {
                some: {
                  teamId: {
                    in: activeOn
                  },
                  accepted: true
                }
              }
            },
            eventType: {
              teamId: null,
              parentId: null
              // children managed event types are handled above with team event types
            },
            // if user is already part of an already scheduled activeOn connecting reminders are already scheduled
            NOT: {
              user: {
                teams: {
                  some: {
                    teamId: {
                      in: alreadyScheduledActiveOnIds
                    }
                  }
                }
              }
            }
          }
        ],
        status: BookingStatus.ACCEPTED,
        startTime: {
          gte: /* @__PURE__ */ new Date()
        }
      },
      select: bookingSelect,
      orderBy: {
        startTime: "asc"
      }
    });
    return bookingsForReminders;
  } else {
    const bookingsForReminders = await prisma.booking.findMany({
      where: {
        OR: [
          { eventTypeId: { in: activeOn } },
          {
            eventType: {
              parentId: {
                in: activeOn
                // child event type can not disable workflows, so this should work
              }
            }
          }
        ],
        status: BookingStatus.ACCEPTED,
        startTime: {
          gte: /* @__PURE__ */ new Date()
        }
      },
      select: bookingSelect,
      orderBy: {
        startTime: "asc"
      }
    });
    return bookingsForReminders;
  }
}
async function scheduleBookingReminders(bookings, workflowSteps, time, timeUnit, trigger, userId, teamId, isOrg) {
  if (!bookings.length)
    return;
  if (trigger !== WorkflowTriggerEvents.BEFORE_EVENT && trigger !== WorkflowTriggerEvents.AFTER_EVENT)
    return;
  const bookerUrl = await getBookerBaseUrl(isOrg ? teamId : null);
  const promiseSteps = workflowSteps.map(async (step) => {
    const promiseScheduleReminders = bookings.map(async (booking) => {
      const defaultLocale = "en";
      const bookingInfo = {
        uid: booking.uid,
        bookerUrl,
        type: booking.eventType?.slug || "event",
        attendees: booking.attendees.map((attendee) => {
          return {
            name: attendee.name,
            email: attendee.email,
            timeZone: attendee.timeZone,
            language: { locale: attendee.locale || defaultLocale }
          };
        }),
        organizer: booking.user ? {
          language: { locale: booking.user.locale || defaultLocale },
          name: booking.user.name || "",
          email: booking?.userPrimaryEmail ?? booking.user.email,
          timeZone: booking.user.timeZone,
          timeFormat: getTimeFormatStringFromUserTimeFormat(booking.user.timeFormat)
        } : { name: "", email: "", timeZone: "", language: { locale: "" } },
        startTime: booking.startTime?.toISOString(),
        endTime: booking.endTime?.toISOString(),
        title: booking.title,
        language: { locale: booking?.user?.locale || defaultLocale },
        hideOrganizerEmail: booking.eventType?.hideOrganizerEmail,
        eventType: {
          slug: booking.eventType?.slug || "",
          schedulingType: booking.eventType?.schedulingType,
          hosts: booking.eventType?.hosts
        },
        metadata: booking.metadata,
        customReplyToEmail: booking.eventType?.customReplyToEmail,
        responses: booking.responses
      };
      if (step.action === WorkflowActions.EMAIL_HOST || step.action === WorkflowActions.EMAIL_ATTENDEE || step.action === WorkflowActions.EMAIL_ADDRESS) {
        let sendTo = [];
        switch (step.action) {
          case WorkflowActions.EMAIL_HOST:
            sendTo = [bookingInfo.organizer?.email];
            const schedulingType = bookingInfo.eventType.schedulingType;
            const hosts = bookingInfo.eventType.hosts?.filter((host) => bookingInfo.attendees.some((attendee) => attendee.email === host.user.email)).map(({ user }) => user.destinationCalendar?.primaryEmail ?? user.email);
            if (hosts && (schedulingType === SchedulingType.ROUND_ROBIN || schedulingType === SchedulingType.COLLECTIVE)) {
              sendTo = sendTo.concat(hosts);
            }
            break;
          case WorkflowActions.EMAIL_ATTENDEE:
            sendTo = bookingInfo.attendees.map((attendee) => attendee.email);
            break;
          case WorkflowActions.EMAIL_ADDRESS:
            await verifyEmailSender(step.sendTo || "", userId, teamId);
            sendTo = [step.sendTo || ""];
            break;
        }
        await scheduleEmailReminder({
          evt: bookingInfo,
          triggerEvent: trigger,
          action: step.action,
          timeSpan: {
            time,
            timeUnit
          },
          sendTo,
          emailSubject: step.emailSubject || "",
          emailBody: step.reminderBody || "",
          template: step.template,
          sender: step.sender,
          workflowStepId: step.id,
          verifiedAt: step?.verifiedAt ?? null
        });
      } else if (step.action === WorkflowActions.SMS_NUMBER && step.sendTo) {
        await scheduleSMSReminder({
          evt: bookingInfo,
          reminderPhone: step.sendTo,
          triggerEvent: trigger,
          action: step.action,
          timeSpan: {
            time,
            timeUnit
          },
          message: step.reminderBody || "",
          workflowStepId: step.id,
          template: step.template,
          sender: step.sender,
          userId,
          teamId,
          verifiedAt: step?.verifiedAt ?? null
        });
      } else if (step.action === WorkflowActions.WHATSAPP_NUMBER && step.sendTo) {
        await scheduleWhatsappReminder({
          evt: bookingInfo,
          reminderPhone: step.sendTo,
          triggerEvent: trigger,
          action: step.action,
          timeSpan: {
            time,
            timeUnit
          },
          message: step.reminderBody || "",
          workflowStepId: step.id || 0,
          template: step.template,
          userId,
          teamId,
          verifiedAt: step?.verifiedAt ?? null
        });
      } else if (booking.smsReminderNumber) {
        if (step.action === WorkflowActions.SMS_ATTENDEE) {
          await scheduleSMSReminder({
            evt: bookingInfo,
            reminderPhone: booking.smsReminderNumber,
            triggerEvent: trigger,
            action: step.action,
            timeSpan: {
              time,
              timeUnit
            },
            message: step.reminderBody || "",
            workflowStepId: step.id,
            template: step.template,
            sender: step.sender,
            userId,
            teamId,
            verifiedAt: step?.verifiedAt ?? null
          });
        } else if (step.action === WorkflowActions.WHATSAPP_ATTENDEE) {
          await scheduleWhatsappReminder({
            evt: bookingInfo,
            reminderPhone: booking.smsReminderNumber,
            triggerEvent: trigger,
            action: step.action,
            timeSpan: {
              time,
              timeUnit
            },
            message: step.reminderBody || "",
            workflowStepId: step.id,
            template: step.template,
            sender: step.sender,
            userId,
            teamId,
            verifiedAt: step?.verifiedAt ?? null
          });
        }
      } else if (step.action === WorkflowActions.CAL_AI_PHONE_CALL) {
        await scheduleAIPhoneCall({
          evt: bookingInfo,
          triggerEvent: trigger,
          timeSpan: {
            time,
            timeUnit
          },
          workflowStepId: step.id,
          userId,
          teamId,
          verifiedAt: step?.verifiedAt ?? null
        });
      }
    });
    await Promise.all(promiseScheduleReminders);
  });
  return Promise.all(promiseSteps);
}
function isStepEdited(oldStep, newStep) {
  const oldStepKeys = Object.keys(oldStep);
  const newStepKeys = Object.keys(newStep);
  if (oldStepKeys.length !== newStepKeys.length) {
    return true;
  }
  for (const key of oldStepKeys) {
    if (oldStep[key] !== newStep[key]) {
      return true;
    }
  }
  return false;
}
async function getAllWorkflowsFromEventType(eventType, userId) {
  if (!eventType)
    return [];
  const eventTypeWorkflows = eventType?.workflows?.map((workflowRel) => workflowRel.workflow) ?? [];
  const teamId = await getTeamIdFromEventType({
    eventType: {
      team: { id: eventType?.teamId ?? null },
      parentId: eventType?.parentId || eventType?.parent?.id || null
    }
  });
  const orgId = await getOrgIdFromMemberOrTeamId({ memberId: userId, teamId });
  const isManagedEventType = !!eventType?.parent;
  const eventTypeMetadata = EventTypeMetaDataSchema.parse(eventType?.metadata || {});
  const workflowsLockedForUser = isManagedEventType ? !eventTypeMetadata?.managedEventConfig?.unlockedFields?.workflows : false;
  const allWorkflows = await getAllWorkflows(
    eventTypeWorkflows,
    userId,
    teamId,
    orgId,
    workflowsLockedForUser
  );
  return allWorkflows;
}
async function getEmailTemplateText(template, params) {
  const { locale, action } = params;
  const timeFormat = getTimeFormatStringFromUserTimeFormat(params.timeFormat);
  let { emailBody, emailSubject } = emailReminderTemplate({
    isEditingMode: true,
    locale,
    t: await getTranslation(locale ?? "en", "common"),
    action,
    timeFormat
  });
  if (template === WorkflowTemplates.RATING) {
    const ratingTemplate = emailRatingTemplate({
      isEditingMode: true,
      locale,
      action,
      t: await getTranslation(locale ?? "en", "common"),
      timeFormat
    });
    emailBody = ratingTemplate.emailBody;
    emailSubject = ratingTemplate.emailSubject;
  }
  return { emailBody, emailSubject };
}
const hashAPIKey = (apiKey) => createHash("sha256").update(apiKey).digest("hex");
const generateUniqueAPIKey = (apiKey = randomBytes(16).toString("hex")) => [
  hashAPIKey(apiKey),
  apiKey
];
const timeZoneSchema = z.string().refine((timeZone) => isSupportedTimeZone(timeZone), {
  message: "Invalid timezone. Must be a valid IANA timezone string."
});
const templateTypeEnum = z__default.enum(["CHECK_IN_APPOINTMENT", "CUSTOM_TEMPLATE"]);
const requiredFields = z__default.object({
  yourPhoneNumber: z__default.string().refine((val) => isValidPhoneNumber(val)),
  numberToCall: z__default.string().refine((val) => isValidPhoneNumber(val)),
  calApiKey: z__default.string().trim().min(1, {
    message: "Please enter CAL API Key"
  }),
  eventTypeId: z__default.number(),
  enabled: z__default.boolean().default(false),
  templateType: templateTypeEnum
});
const createPhoneCallSchema = requiredFields.merge(
  z__default.object({
    schedulerName: z__default.string().min(1).optional().nullable(),
    guestName: z__default.string().optional().transform((val) => {
      return !!val ? val : void 0;
    }),
    guestEmail: z__default.string().optional().transform((val) => {
      return !!val ? val : void 0;
    }),
    guestCompany: z__default.string().optional().transform((val) => {
      return !!val ? val : void 0;
    }),
    beginMessage: z__default.string().optional(),
    generalPrompt: z__default.string().optional()
  })
);
const ZGetPhoneNumberSchema = z__default.object({
  phone_number: z__default.string(),
  agent_id: z__default.string().optional(),
  nickname: z__default.string(),
  inbound_agent_id: z__default.string(),
  outbound_agent_id: z__default.string(),
  error_message: z__default.string().optional()
}).passthrough();
const ZCreatePhoneSchema = z__default.object({
  call_id: z__default.string(),
  agent_id: z__default.string().optional()
}).passthrough();
({
  CHECK_IN_APPOINTMENT: requiredFields.merge(
    z__default.object({
      schedulerName: z__default.string().min(1)
    })
  ),
  CUSTOM_TEMPLATE: createPhoneCallSchema.omit({ generalPrompt: true }).merge(
    z__default.object({
      generalPrompt: z__default.string()
    })
  )
});
const fieldTypeEnum = z__default.enum([
  "name",
  "text",
  "textarea",
  "number",
  "email",
  "phone",
  "address",
  "multiemail",
  "select",
  "multiselect",
  "checkbox",
  "radio",
  "radioInput",
  "boolean"
]);
const fieldNameEnum = z__default.enum([
  "schedulerName",
  "generalPrompt",
  "guestName",
  "guestEmail",
  "guestCompany",
  "beginMessage"
]);
const FieldSchema = z__default.object({
  type: fieldTypeEnum,
  name: fieldNameEnum,
  required: z__default.boolean(),
  defaultLabel: z__default.string(),
  placeholder: z__default.string(),
  variableName: z__default.string().optional()
});
z__default.array(FieldSchema);
const ZCreateRetellLLMSchema = z__default.object({
  llm_id: z__default.string(),
  llm_websocket_url: z__default.string().optional(),
  inbound_dynamic_variables_webhook_url: z__default.string().optional()
}).passthrough();
const ZGetRetellLLMSchema = z__default.object({
  general_prompt: z__default.string(),
  begin_message: z__default.string().nullable().optional(),
  llm_id: z__default.string(),
  llm_websocket_url: z__default.string().optional(),
  inbound_dynamic_variables_webhook_url: z__default.string().optional(),
  general_tools: z__default.array(
    z__default.object({
      name: z__default.string(),
      type: z__default.string(),
      cal_api_key: z__default.string().optional(),
      event_type_id: z__default.number().optional(),
      timezone: z__default.string().optional()
    }).passthrough()
  ),
  states: z__default.array(
    z__default.object({
      name: z__default.string(),
      tools: z__default.array(
        z__default.object({
          name: z__default.string(),
          type: z__default.string(),
          cal_api_key: z__default.string().optional(),
          event_type_id: z__default.number().optional(),
          timezone: z__default.string().optional()
        }).passthrough()
      )
    }).passthrough()
  ).nullable().optional()
}).passthrough();
z__default.object({
  phone_number: z__default.string(),
  phone_number_type: z__default.string(),
  phone_number_pretty: z__default.string(),
  inbound_agent_id: z__default.string().optional().nullable(),
  outbound_agent_id: z__default.string().optional().nullable(),
  inbound_agent_version: z__default.number().optional().nullable(),
  outbound_agent_version: z__default.number().optional().nullable(),
  area_code: z__default.number().optional().nullable(),
  nickname: z__default.string(),
  inbound_webhook_url: z__default.string().url().optional().nullable(),
  last_modification_timestamp: z__default.number()
});
z__default.object({
  agent_id: z__default.string(),
  agent_name: z__default.string()
});
const PROMPT_TEMPLATES = {
  [templateTypeEnum.enum.CHECK_IN_APPOINTMENT]: {
    generalPrompt: `## Identity
You are {{scheduler_name}}'s virtual assistant named Chloe, calling to notify user of a scheduled appointment. You are a pleasant and friendly assistant, here to help manage calendar notifications.

## Style Guardrails
Be Concise: Respond succinctly, addressing one topic at most.
Embrace Variety: Use diverse language and rephrasing to enhance clarity without repeating content.
Be Conversational: Use everyday language, making the chat feel like talking to a friend.
Be Proactive: Lead the conversation, often wrapping up with a question or next-step suggestion.
Avoid multiple questions in a single response.
Get clarity: If the user only partially answers a question, or if the answer is unclear, keep asking to get clarity.
Use a colloquial way of referring to the date (like 'next Friday', 'tomorrow').
One question at a time: Ask only one question at a time, do not pack more topics into one response.

## Response Guideline
Adapt and Guess: Try to understand transcripts that may contain transcription errors. Avoid mentioning "transcription error" in the response.
Stay in Character: Keep conversations within your role's scope, guiding them back creatively without repeating.
Ensure Fluid Dialogue: Respond in a role-appropriate, direct manner to maintain a smooth conversation flow.
Do not make up answers: If you do not know the answer to a question, simply say so. Do not fabricate or deviate from listed responses.
If at any moment the conversation deviates, kindly lead it back to the relevant topic. Do not repeat from start, keep asking from where you stopped.`
  }
};
const DEFAULT_PROMPT_VALUE = `## You are helping user set up a call with the support team. The appointment is 15 min long. You are a pleasant and friendly.

  ## Style Guardrails
  Be Concise: Respond succinctly, addressing one topic at most.
  Embrace Variety: Use diverse language and rephrasing to enhance clarity without repeating content.
  Be Conversational: Use everyday language, making the chat feel like talking to a friend.
  Be Proactive: Lead the conversation, often wrapping up with a question or next-step suggestion.
  Avoid multiple questions in a single response.
  Get clarity: If the user only partially answers a question, or if the answer is unclear, keep asking to get clarity.
  Use a colloquial way of referring to the date (like Friday, Jan 14th, or Tuesday, Jan 12th, 2024 at 8am).
  If you are saying a time like 8:00 AM, just say 8 AM and emit the trailing zeros.

  ## Response Guideline
  Adapt and Guess: Try to understand transcripts that may contain transcription errors. Avoid mentioning "transcription error" in the response.
  Stay in Character: Keep conversations within your role'''s scope, guiding them back creatively without repeating.
  Ensure Fluid Dialogue: Respond in a role-appropriate, direct manner to maintain a smooth conversation flow.

  ## Schedule Rule
  Current time is {{current_time}}. You only schedule time in current calendar year, you cannot schedule time that'''s in the past.

  ## Task Steps
  1. I am here to learn more about your issue and help schedule an appointment with our support team.
  2. If {{ATTENDEE_EMAIL}} is not unknown then Use name {{ATTENDEE_NAME}} and email {{ATTENDEE_EMAIL}} for creating booking else Ask for user name and email and Confirm the name and email with user by reading it back to user.
  3. Ask user for "When would you want to meet with one of our representatives".
  4. Call function check_availability_{{eventTypeId}} to check for availability in the user provided time range.
    - if availability exists, inform user about the availability range (do not repeat the detailed available slot) and ask user to choose from it. Make sure user chose a slot within detailed available slot.
    - if availability does not exist, ask user to select another time range for the appointment, repeat this step 3.
  5. Confirm the date and time selected by user: "Just to confirm, you want to book the appointment at ...".
  6. Once confirmed, call function book_appointment_{{eventTypeId}} to book the appointment.
    - if booking returned booking detail, it means booking is successful, proceed to step 7.
    - if booking returned error message, let user know why the booking was not successful, and maybe start over with step 3.
  7. Inform the user booking is successful, and ask if user have any questions. Answer them if there are any.
  8. After all questions answered, call function end_call to hang up.`;
const DEFAULT_BEGIN_MESSAGE = "Hi. How are you doing?";
export {
  DEFAULT_PROMPT_VALUE as D,
  PROMPT_TEMPLATES as P,
  WorkflowRepository as W,
  ZCreateRetellLLMSchema as Z,
  DEFAULT_BEGIN_MESSAGE as a,
  isAuthorizedToAddActiveOnIds as b,
  getSender as c,
  deleteRemindersOfActiveOnIds as d,
  isStepEdited as e,
  getEmailTemplateText as f,
  generateUniqueAPIKey as g,
  removeAIAgentCallPhoneNumberFieldForEventTypes as h,
  isAuthorized as i,
  upsertAIAgentCallPhoneNumberFieldForEventTypes as j,
  getTeamIdFromEventType as k,
  getAllWorkflowsFromEventType as l,
  ZGetRetellLLMSchema as m,
  ZGetPhoneNumberSchema as n,
  ZCreatePhoneSchema as o,
  templateTypeEnum as p,
  removeSmsReminderFieldForEventTypes as r,
  scheduleWorkflowNotifications as s,
  timeZoneSchema as t,
  upsertSmsReminderFieldForEventTypes as u,
  verifyEmailSender as v,
  workflowSelect as w
};
