"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const ICAL = require("ical.js");
require("./index-Br7AzmuA.cjs");
const index = require("./i18n-HHdcQbuJ.cjs");
const dayjs = require("dayjs");
const getTravelDurationInSeconds = (vevent) => {
  const travelDuration = vevent.getFirstPropertyValue("x-apple-travel-duration");
  if (!travelDuration)
    return 0;
  try {
    const travelSeconds = travelDuration.toSeconds();
    if (!Number.isInteger(travelSeconds))
      return 0;
    return travelSeconds;
  } catch (e) {
    return 0;
  }
};
const applyTravelDuration = (event, seconds) => {
  if (seconds <= 0)
    return event;
  event.startDate.second -= seconds;
  return event;
};
const CALENDSO_ENCRYPTION_KEY = process.env.CALENDSO_ENCRYPTION_KEY || "";
class ICSFeedCalendarService {
  constructor(credential) {
    this.urls = [];
    this.integrationName = "ics-feed_calendar";
    this.fetchCalendars = async () => {
      const reqPromises = await Promise.allSettled(this.urls.map((x) => fetch(x).then((y) => [x, y])));
      const reqs = reqPromises.filter((x) => x.status === "fulfilled").map((x) => x.value);
      const res = await Promise.all(reqs.map((x) => x[1].text().then((y) => [x[0], y])));
      return res.map((x) => {
        try {
          const jcalData = ICAL.parse(x[1]);
          return {
            url: x[0],
            vcalendar: new ICAL.Component(jcalData)
          };
        } catch (e) {
          console.error("Error parsing calendar object: ", e);
          return null;
        }
      }).filter((x) => x !== null);
    };
    this.getUserTimezoneFromDB = async (id) => {
      const prisma = await Promise.resolve().then(() => require("./i18n-HHdcQbuJ.cjs")).then((n) => n.index).then((mod) => mod.default);
      const user = await prisma.user.findUnique({
        where: {
          id
        },
        select: {
          timeZone: true
        }
      });
      return user?.timeZone;
    };
    this.getUserId = (selectedCalendars) => {
      if (selectedCalendars.length === 0) {
        return null;
      }
      return selectedCalendars[0].userId || null;
    };
    const { urls } = JSON.parse(index.symmetricDecrypt(credential.key, CALENDSO_ENCRYPTION_KEY));
    this.urls = urls;
  }
  createEvent(_event, _credentialId) {
    console.warn("createEvent called on ICS (read-only) feed");
    return Promise.resolve({
      uid: _event.uid || "",
      type: this.integrationName,
      id: "",
      password: "",
      url: "",
      additionalInfo: { calWarnings: ["ICS feed is read-only"] }
    });
  }
  deleteEvent(_uid, _event, _externalCalendarId) {
    console.warn("deleteEvent called on ICS (read-only) feed");
    return Promise.resolve();
  }
  updateEvent(_uid, _event, _externalCalendarId) {
    console.warn("updateEvent called on ICS (read-only) feed");
    return Promise.resolve({
      uid: _event.uid || "",
      type: this.integrationName,
      id: "",
      password: "",
      url: "",
      additionalInfo: { calWarnings: ["ICS feed is read-only"] }
    });
  }
  async getAvailability(dateFrom, dateTo, selectedCalendars) {
    const startISOString = new Date(dateFrom).toISOString();
    const calendars = await this.fetchCalendars();
    const userId = this.getUserId(selectedCalendars);
    const userTimeZone = userId ? await this.getUserTimezoneFromDB(userId) : "Europe/London";
    const events = [];
    calendars.forEach(({ vcalendar }) => {
      const vevents = vcalendar.getAllSubcomponents("vevent");
      vevents.forEach((vevent) => {
        const event = new ICAL.Event(vevent);
        const dtstartProperty = vevent.getFirstProperty("dtstart");
        const tzidFromDtstart = dtstartProperty ? dtstartProperty.jCal[1].tzid : void 0;
        const dtstart = vevent?.getFirstPropertyValue("dtstart");
        const timezone = dtstart ? dtstart["timezone"] : void 0;
        const isUTC = timezone === "Z";
        const tzid = tzidFromDtstart || vevent?.getFirstPropertyValue("tzid") || (isUTC ? "UTC" : timezone);
        if (!vcalendar.getFirstSubcomponent("vtimezone")) {
          const timezoneToUse = tzid || userTimeZone;
          if (timezoneToUse) {
            try {
              const timezoneComp = new ICAL.Component("vtimezone");
              timezoneComp.addPropertyWithValue("tzid", timezoneToUse);
              const standard = new ICAL.Component("standard");
              const tzoffsetfrom = dayjs(event.startDate.toJSDate()).tz(timezoneToUse).format("Z");
              const tzoffsetto = dayjs(event.endDate.toJSDate()).tz(timezoneToUse).format("Z");
              standard.addPropertyWithValue("tzoffsetfrom", tzoffsetfrom);
              standard.addPropertyWithValue("tzoffsetto", tzoffsetto);
              standard.addPropertyWithValue("dtstart", "1601-01-01T00:00:00");
              timezoneComp.addSubcomponent(standard);
              vcalendar.addSubcomponent(timezoneComp);
            } catch (e) {
              console.log("error in adding vtimezone", e);
            }
          } else {
            console.error("No timezone found");
          }
        }
        let vtimezone = null;
        if (tzid) {
          const allVtimezones = vcalendar.getAllSubcomponents("vtimezone");
          vtimezone = allVtimezones.find((vtz) => vtz.getFirstPropertyValue("tzid") === tzid);
        }
        if (!vtimezone) {
          vtimezone = vcalendar.getFirstSubcomponent("vtimezone");
        }
        applyTravelDuration(event, getTravelDurationInSeconds(vevent));
        if (event.isRecurring()) {
          let maxIterations = 365;
          if (["HOURLY", "SECONDLY", "MINUTELY"].includes(event.getRecurrenceTypes())) {
            console.error(`Won't handle [${event.getRecurrenceTypes()}] recurrence`);
            return;
          }
          const start = dayjs(dateFrom);
          const end = dayjs(dateTo);
          const startDate = ICAL.Time.fromDateTimeString(startISOString);
          startDate.hour = event.startDate.hour;
          startDate.minute = event.startDate.minute;
          startDate.second = event.startDate.second;
          const iterator = event.iterator(startDate);
          let current;
          let currentEvent;
          let currentStart = null;
          let currentError;
          while (maxIterations > 0 && (currentStart === null || currentStart.isAfter(end) === false) && // this iterator was poorly implemented, normally done is expected to be
          // returned
          (current = iterator.next())) {
            maxIterations -= 1;
            try {
              currentEvent = event.getOccurrenceDetails(current);
            } catch (error) {
              if (error instanceof Error && error.message !== currentError) {
                currentError = error.message;
              }
            }
            if (!currentEvent)
              return;
            if (vtimezone) {
              const zone = new ICAL.Timezone(vtimezone);
              currentEvent.startDate = currentEvent.startDate.convertToZone(zone);
              currentEvent.endDate = currentEvent.endDate.convertToZone(zone);
            }
            currentStart = dayjs(currentEvent.startDate.toJSDate());
            if (currentStart.isBetween(start, end) === true) {
              events.push({
                start: currentStart.toISOString(),
                end: dayjs(currentEvent.endDate.toJSDate()).toISOString()
              });
            }
          }
          if (maxIterations <= 0) {
            console.warn("could not find any occurrence for recurring event in 365 iterations");
          }
          return;
        }
        if (vtimezone) {
          const zone = new ICAL.Timezone(vtimezone);
          event.startDate = event.startDate.convertToZone(zone);
          event.endDate = event.endDate.convertToZone(zone);
        }
        const finalStartISO = dayjs(event.startDate.toJSDate()).toISOString();
        const finalEndISO = dayjs(event.endDate.toJSDate()).toISOString();
        return events.push({
          start: finalStartISO,
          end: finalEndISO
        });
      });
    });
    return Promise.resolve(events);
  }
  async listCalendars() {
    const vcals = await this.fetchCalendars();
    return vcals.map(({ url, vcalendar }) => {
      const name = vcalendar.getFirstPropertyValue("x-wr-calname");
      return {
        name,
        readOnly: true,
        externalId: url,
        integrationName: this.integrationName
      };
    });
  }
}
exports.default = ICSFeedCalendarService;
