var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// node_modules/dayjs/dayjs.min.js
var require_dayjs_min = __commonJS({
  "node_modules/dayjs/dayjs.min.js"(exports, module) {
    !(function(t, e) {
      "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
    })(exports, (function() {
      "use strict";
      var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(t2) {
        var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
        return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
      } }, m = function(t2, e2, n2) {
        var r2 = String(t2);
        return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
      }, v = { s: m, z: function(t2) {
        var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
        return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
      }, m: function t2(e2, n2) {
        if (e2.date() < n2.date()) return -t2(n2, e2);
        var r2 = 12 * (n2.year() - e2.year()) + (n2.month() - e2.month()), i2 = e2.clone().add(r2, c), s2 = n2 - i2 < 0, u2 = e2.clone().add(r2 + (s2 ? -1 : 1), c);
        return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
      }, a: function(t2) {
        return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
      }, p: function(t2) {
        return { M: c, y: h, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: f }[t2] || String(t2 || "").toLowerCase().replace(/s$/, "");
      }, u: function(t2) {
        return void 0 === t2;
      } }, g = "en", D = {};
      D[g] = M;
      var p = "$isDayjsObject", S = function(t2) {
        return t2 instanceof _ || !(!t2 || !t2[p]);
      }, w = function t2(e2, n2, r2) {
        var i2;
        if (!e2) return g;
        if ("string" == typeof e2) {
          var s2 = e2.toLowerCase();
          D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
          var u2 = e2.split("-");
          if (!i2 && u2.length > 1) return t2(u2[0]);
        } else {
          var a2 = e2.name;
          D[a2] = e2, i2 = a2;
        }
        return !r2 && i2 && (g = i2), i2 || !r2 && g;
      }, O = function(t2, e2) {
        if (S(t2)) return t2.clone();
        var n2 = "object" == typeof e2 ? e2 : {};
        return n2.date = t2, n2.args = arguments, new _(n2);
      }, b = v;
      b.l = w, b.i = S, b.w = function(t2, e2) {
        return O(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
      };
      var _ = (function() {
        function M2(t2) {
          this.$L = w(t2.locale, null, true), this.parse(t2), this.$x = this.$x || t2.x || {}, this[p] = true;
        }
        var m2 = M2.prototype;
        return m2.parse = function(t2) {
          this.$d = (function(t3) {
            var e2 = t3.date, n2 = t3.utc;
            if (null === e2) return /* @__PURE__ */ new Date(NaN);
            if (b.u(e2)) return /* @__PURE__ */ new Date();
            if (e2 instanceof Date) return new Date(e2);
            if ("string" == typeof e2 && !/Z$/i.test(e2)) {
              var r2 = e2.match($);
              if (r2) {
                var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
                return n2 ? new Date(Date.UTC(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2)) : new Date(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2);
              }
            }
            return new Date(e2);
          })(t2), this.init();
        }, m2.init = function() {
          var t2 = this.$d;
          this.$y = t2.getFullYear(), this.$M = t2.getMonth(), this.$D = t2.getDate(), this.$W = t2.getDay(), this.$H = t2.getHours(), this.$m = t2.getMinutes(), this.$s = t2.getSeconds(), this.$ms = t2.getMilliseconds();
        }, m2.$utils = function() {
          return b;
        }, m2.isValid = function() {
          return !(this.$d.toString() === l);
        }, m2.isSame = function(t2, e2) {
          var n2 = O(t2);
          return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
        }, m2.isAfter = function(t2, e2) {
          return O(t2) < this.startOf(e2);
        }, m2.isBefore = function(t2, e2) {
          return this.endOf(e2) < O(t2);
        }, m2.$g = function(t2, e2, n2) {
          return b.u(t2) ? this[e2] : this.set(n2, t2);
        }, m2.unix = function() {
          return Math.floor(this.valueOf() / 1e3);
        }, m2.valueOf = function() {
          return this.$d.getTime();
        }, m2.startOf = function(t2, e2) {
          var n2 = this, r2 = !!b.u(e2) || e2, f2 = b.p(t2), l2 = function(t3, e3) {
            var i2 = b.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
            return r2 ? i2 : i2.endOf(a);
          }, $2 = function(t3, e3) {
            return b.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
          }, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
          switch (f2) {
            case h:
              return r2 ? l2(1, 0) : l2(31, 11);
            case c:
              return r2 ? l2(1, M3) : l2(0, M3 + 1);
            case o:
              var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
              return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
            case a:
            case d:
              return $2(v2 + "Hours", 0);
            case u:
              return $2(v2 + "Minutes", 1);
            case s:
              return $2(v2 + "Seconds", 2);
            case i:
              return $2(v2 + "Milliseconds", 3);
            default:
              return this.clone();
          }
        }, m2.endOf = function(t2) {
          return this.startOf(t2, false);
        }, m2.$set = function(t2, e2) {
          var n2, o2 = b.p(t2), f2 = "set" + (this.$u ? "UTC" : ""), l2 = (n2 = {}, n2[a] = f2 + "Date", n2[d] = f2 + "Date", n2[c] = f2 + "Month", n2[h] = f2 + "FullYear", n2[u] = f2 + "Hours", n2[s] = f2 + "Minutes", n2[i] = f2 + "Seconds", n2[r] = f2 + "Milliseconds", n2)[o2], $2 = o2 === a ? this.$D + (e2 - this.$W) : e2;
          if (o2 === c || o2 === h) {
            var y2 = this.clone().set(d, 1);
            y2.$d[l2]($2), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
          } else l2 && this.$d[l2]($2);
          return this.init(), this;
        }, m2.set = function(t2, e2) {
          return this.clone().$set(t2, e2);
        }, m2.get = function(t2) {
          return this[b.p(t2)]();
        }, m2.add = function(r2, f2) {
          var d2, l2 = this;
          r2 = Number(r2);
          var $2 = b.p(f2), y2 = function(t2) {
            var e2 = O(l2);
            return b.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
          };
          if ($2 === c) return this.set(c, this.$M + r2);
          if ($2 === h) return this.set(h, this.$y + r2);
          if ($2 === a) return y2(1);
          if ($2 === o) return y2(7);
          var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$2] || 1, m3 = this.$d.getTime() + r2 * M3;
          return b.w(m3, this);
        }, m2.subtract = function(t2, e2) {
          return this.add(-1 * t2, e2);
        }, m2.format = function(t2) {
          var e2 = this, n2 = this.$locale();
          if (!this.isValid()) return n2.invalidDate || l;
          var r2 = t2 || "YYYY-MM-DDTHH:mm:ssZ", i2 = b.z(this), s2 = this.$H, u2 = this.$m, a2 = this.$M, o2 = n2.weekdays, c2 = n2.months, f2 = n2.meridiem, h2 = function(t3, n3, i3, s3) {
            return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
          }, d2 = function(t3) {
            return b.s(s2 % 12 || 12, t3, "0");
          }, $2 = f2 || function(t3, e3, n3) {
            var r3 = t3 < 12 ? "AM" : "PM";
            return n3 ? r3.toLowerCase() : r3;
          };
          return r2.replace(y, (function(t3, r3) {
            return r3 || (function(t4) {
              switch (t4) {
                case "YY":
                  return String(e2.$y).slice(-2);
                case "YYYY":
                  return b.s(e2.$y, 4, "0");
                case "M":
                  return a2 + 1;
                case "MM":
                  return b.s(a2 + 1, 2, "0");
                case "MMM":
                  return h2(n2.monthsShort, a2, c2, 3);
                case "MMMM":
                  return h2(c2, a2);
                case "D":
                  return e2.$D;
                case "DD":
                  return b.s(e2.$D, 2, "0");
                case "d":
                  return String(e2.$W);
                case "dd":
                  return h2(n2.weekdaysMin, e2.$W, o2, 2);
                case "ddd":
                  return h2(n2.weekdaysShort, e2.$W, o2, 3);
                case "dddd":
                  return o2[e2.$W];
                case "H":
                  return String(s2);
                case "HH":
                  return b.s(s2, 2, "0");
                case "h":
                  return d2(1);
                case "hh":
                  return d2(2);
                case "a":
                  return $2(s2, u2, true);
                case "A":
                  return $2(s2, u2, false);
                case "m":
                  return String(u2);
                case "mm":
                  return b.s(u2, 2, "0");
                case "s":
                  return String(e2.$s);
                case "ss":
                  return b.s(e2.$s, 2, "0");
                case "SSS":
                  return b.s(e2.$ms, 3, "0");
                case "Z":
                  return i2;
              }
              return null;
            })(t3) || i2.replace(":", "");
          }));
        }, m2.utcOffset = function() {
          return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
        }, m2.diff = function(r2, d2, l2) {
          var $2, y2 = this, M3 = b.p(d2), m3 = O(r2), v2 = (m3.utcOffset() - this.utcOffset()) * e, g2 = this - m3, D2 = function() {
            return b.m(y2, m3);
          };
          switch (M3) {
            case h:
              $2 = D2() / 12;
              break;
            case c:
              $2 = D2();
              break;
            case f:
              $2 = D2() / 3;
              break;
            case o:
              $2 = (g2 - v2) / 6048e5;
              break;
            case a:
              $2 = (g2 - v2) / 864e5;
              break;
            case u:
              $2 = g2 / n;
              break;
            case s:
              $2 = g2 / e;
              break;
            case i:
              $2 = g2 / t;
              break;
            default:
              $2 = g2;
          }
          return l2 ? $2 : b.a($2);
        }, m2.daysInMonth = function() {
          return this.endOf(c).$D;
        }, m2.$locale = function() {
          return D[this.$L];
        }, m2.locale = function(t2, e2) {
          if (!t2) return this.$L;
          var n2 = this.clone(), r2 = w(t2, e2, true);
          return r2 && (n2.$L = r2), n2;
        }, m2.clone = function() {
          return b.w(this.$d, this);
        }, m2.toDate = function() {
          return new Date(this.valueOf());
        }, m2.toJSON = function() {
          return this.isValid() ? this.toISOString() : null;
        }, m2.toISOString = function() {
          return this.$d.toISOString();
        }, m2.toString = function() {
          return this.$d.toUTCString();
        }, M2;
      })(), k = _.prototype;
      return O.prototype = k, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", c], ["$y", h], ["$D", d]].forEach((function(t2) {
        k[t2[1]] = function(e2) {
          return this.$g(e2, t2[0], t2[1]);
        };
      })), O.extend = function(t2, e2) {
        return t2.$i || (t2(e2, _, O), t2.$i = true), O;
      }, O.locale = w, O.isDayjs = S, O.unix = function(t2) {
        return O(1e3 * t2);
      }, O.en = D[g], O.Ls = D, O.p = {}, O;
    }));
  }
});

// node_modules/dayjs/plugin/utc.js
var require_utc = __commonJS({
  "node_modules/dayjs/plugin/utc.js"(exports, module) {
    !(function(t, i) {
      "object" == typeof exports && "undefined" != typeof module ? module.exports = i() : "function" == typeof define && define.amd ? define(i) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs_plugin_utc = i();
    })(exports, (function() {
      "use strict";
      var t = "minute", i = /[+-]\d\d(?::?\d\d)?/g, e = /([+-]|\d\d)/g;
      return function(s, f, n) {
        var u = f.prototype;
        n.utc = function(t2) {
          var i2 = { date: t2, utc: true, args: arguments };
          return new f(i2);
        }, u.utc = function(i2) {
          var e2 = n(this.toDate(), { locale: this.$L, utc: true });
          return i2 ? e2.add(this.utcOffset(), t) : e2;
        }, u.local = function() {
          return n(this.toDate(), { locale: this.$L, utc: false });
        };
        var r = u.parse;
        u.parse = function(t2) {
          t2.utc && (this.$u = true), this.$utils().u(t2.$offset) || (this.$offset = t2.$offset), r.call(this, t2);
        };
        var o = u.init;
        u.init = function() {
          if (this.$u) {
            var t2 = this.$d;
            this.$y = t2.getUTCFullYear(), this.$M = t2.getUTCMonth(), this.$D = t2.getUTCDate(), this.$W = t2.getUTCDay(), this.$H = t2.getUTCHours(), this.$m = t2.getUTCMinutes(), this.$s = t2.getUTCSeconds(), this.$ms = t2.getUTCMilliseconds();
          } else o.call(this);
        };
        var a = u.utcOffset;
        u.utcOffset = function(s2, f2) {
          var n2 = this.$utils().u;
          if (n2(s2)) return this.$u ? 0 : n2(this.$offset) ? a.call(this) : this.$offset;
          if ("string" == typeof s2 && (s2 = (function(t2) {
            void 0 === t2 && (t2 = "");
            var s3 = t2.match(i);
            if (!s3) return null;
            var f3 = ("" + s3[0]).match(e) || ["-", 0, 0], n3 = f3[0], u3 = 60 * +f3[1] + +f3[2];
            return 0 === u3 ? 0 : "+" === n3 ? u3 : -u3;
          })(s2), null === s2)) return this;
          var u2 = Math.abs(s2) <= 16 ? 60 * s2 : s2;
          if (0 === u2) return this.utc(f2);
          var r2 = this.clone();
          if (f2) return r2.$offset = u2, r2.$u = false, r2;
          var o2 = this.$u ? this.toDate().getTimezoneOffset() : -1 * this.utcOffset();
          return (r2 = this.local().add(u2 + o2, t)).$offset = u2, r2.$x.$localOffset = o2, r2;
        };
        var h = u.format;
        u.format = function(t2) {
          var i2 = t2 || (this.$u ? "YYYY-MM-DDTHH:mm:ss[Z]" : "");
          return h.call(this, i2);
        }, u.valueOf = function() {
          var t2 = this.$utils().u(this.$offset) ? 0 : this.$offset + (this.$x.$localOffset || this.$d.getTimezoneOffset());
          return this.$d.valueOf() - 6e4 * t2;
        }, u.isUTC = function() {
          return !!this.$u;
        }, u.toISOString = function() {
          return this.toDate().toISOString();
        }, u.toString = function() {
          return this.toDate().toUTCString();
        };
        var l = u.toDate;
        u.toDate = function(t2) {
          return "s" === t2 && this.$offset ? n(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate() : l.call(this);
        };
        var c = u.diff;
        u.diff = function(t2, i2, e2) {
          if (t2 && this.$u === t2.$u) return c.call(this, t2, i2, e2);
          var s2 = this.local(), f2 = n(t2).local();
          return c.call(s2, f2, i2, e2);
        };
      };
    }));
  }
});

// node_modules/dayjs/plugin/timezone.js
var require_timezone = __commonJS({
  "node_modules/dayjs/plugin/timezone.js"(exports, module) {
    !(function(t, e) {
      "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs_plugin_timezone = e();
    })(exports, (function() {
      "use strict";
      var t = { year: 0, month: 1, day: 2, hour: 3, minute: 4, second: 5 }, e = {};
      return function(n, i, o) {
        var r, a = function(t2, n2, i2) {
          void 0 === i2 && (i2 = {});
          var o2 = new Date(t2), r2 = (function(t3, n3) {
            void 0 === n3 && (n3 = {});
            var i3 = n3.timeZoneName || "short", o3 = t3 + "|" + i3, r3 = e[o3];
            return r3 || (r3 = new Intl.DateTimeFormat("en-US", { hour12: false, timeZone: t3, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: i3 }), e[o3] = r3), r3;
          })(n2, i2);
          return r2.formatToParts(o2);
        }, u = function(e2, n2) {
          for (var i2 = a(e2, n2), r2 = [], u2 = 0; u2 < i2.length; u2 += 1) {
            var f2 = i2[u2], s2 = f2.type, m = f2.value, c = t[s2];
            c >= 0 && (r2[c] = parseInt(m, 10));
          }
          var d = r2[3], l = 24 === d ? 0 : d, h = r2[0] + "-" + r2[1] + "-" + r2[2] + " " + l + ":" + r2[4] + ":" + r2[5] + ":000", v = +e2;
          return (o.utc(h).valueOf() - (v -= v % 1e3)) / 6e4;
        }, f = i.prototype;
        f.tz = function(t2, e2) {
          void 0 === t2 && (t2 = r);
          var n2, i2 = this.utcOffset(), a2 = this.toDate(), u2 = a2.toLocaleString("en-US", { timeZone: t2 }), f2 = Math.round((a2 - new Date(u2)) / 1e3 / 60), s2 = 15 * -Math.round(a2.getTimezoneOffset() / 15) - f2;
          if (!Number(s2)) n2 = this.utcOffset(0, e2);
          else if (n2 = o(u2, { locale: this.$L }).$set("millisecond", this.$ms).utcOffset(s2, true), e2) {
            var m = n2.utcOffset();
            n2 = n2.add(i2 - m, "minute");
          }
          return n2.$x.$timezone = t2, n2;
        }, f.offsetName = function(t2) {
          var e2 = this.$x.$timezone || o.tz.guess(), n2 = a(this.valueOf(), e2, { timeZoneName: t2 }).find((function(t3) {
            return "timezonename" === t3.type.toLowerCase();
          }));
          return n2 && n2.value;
        };
        var s = f.startOf;
        f.startOf = function(t2, e2) {
          if (!this.$x || !this.$x.$timezone) return s.call(this, t2, e2);
          var n2 = o(this.format("YYYY-MM-DD HH:mm:ss:SSS"), { locale: this.$L });
          return s.call(n2, t2, e2).tz(this.$x.$timezone, true);
        }, o.tz = function(t2, e2, n2) {
          var i2 = n2 && e2, a2 = n2 || e2 || r, f2 = u(+o(), a2);
          if ("string" != typeof t2) return o(t2).tz(a2);
          var s2 = (function(t3, e3, n3) {
            var i3 = t3 - 60 * e3 * 1e3, o2 = u(i3, n3);
            if (e3 === o2) return [i3, e3];
            var r2 = u(i3 -= 60 * (o2 - e3) * 1e3, n3);
            return o2 === r2 ? [i3, o2] : [t3 - 60 * Math.min(o2, r2) * 1e3, Math.max(o2, r2)];
          })(o.utc(t2, i2).valueOf(), f2, a2), m = s2[0], c = s2[1], d = o(m).utcOffset(c);
          return d.$x.$timezone = a2, d;
        }, o.tz.guess = function() {
          return Intl.DateTimeFormat().resolvedOptions().timeZone;
        }, o.tz.setDefault = function(t2) {
          r = t2;
        };
      };
    }));
  }
});

// node_modules/dayjs/plugin/isoWeek.js
var require_isoWeek = __commonJS({
  "node_modules/dayjs/plugin/isoWeek.js"(exports, module) {
    !(function(e, t) {
      "object" == typeof exports && "undefined" != typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define(t) : (e = "undefined" != typeof globalThis ? globalThis : e || self).dayjs_plugin_isoWeek = t();
    })(exports, (function() {
      "use strict";
      var e = "day";
      return function(t, i, s) {
        var a = function(t2) {
          return t2.add(4 - t2.isoWeekday(), e);
        }, d = i.prototype;
        d.isoWeekYear = function() {
          return a(this).year();
        }, d.isoWeek = function(t2) {
          if (!this.$utils().u(t2)) return this.add(7 * (t2 - this.isoWeek()), e);
          var i2, d2, n2, o, r = a(this), u = (i2 = this.isoWeekYear(), d2 = this.$u, n2 = (d2 ? s.utc : s)().year(i2).startOf("year"), o = 4 - n2.isoWeekday(), n2.isoWeekday() > 4 && (o += 7), n2.add(o, e));
          return r.diff(u, "week") + 1;
        }, d.isoWeekday = function(e2) {
          return this.$utils().u(e2) ? this.day() || 7 : this.day(this.day() % 7 ? e2 : e2 - 7);
        };
        var n = d.startOf;
        d.startOf = function(e2, t2) {
          var i2 = this.$utils(), s2 = !!i2.u(t2) || t2;
          return "isoweek" === i2.p(e2) ? s2 ? this.date(this.date() - (this.isoWeekday() - 1)).startOf("day") : this.date(this.date() - 1 - (this.isoWeekday() - 1) + 7).endOf("day") : n.bind(this)(e2, t2);
        };
      };
    }));
  }
});

// node_modules/@novadi/core/dist/token.js
var tokenCounter = 0;
function Token(description) {
  const id = ++tokenCounter;
  const sym = /* @__PURE__ */ Symbol(description ? `Token(${description})` : `Token#${id}`);
  const token2 = {
    symbol: sym,
    description,
    toString() {
      return description ? `Token<${description}>` : `Token<#${id}>`;
    }
  };
  return token2;
}

// node_modules/@novadi/core/dist/errors.js
var ContainerError = class extends Error {
  constructor(message) {
    super(message);
    this.name = "ContainerError";
  }
};
var BindingNotFoundError = class extends ContainerError {
  constructor(tokenDescription, path = []) {
    const pathStr = path.length > 0 ? `
  Dependency path: ${path.join(" -> ")}` : "";
    super(`Token "${tokenDescription}" is not bound or registered in the container.${pathStr}`);
    this.name = "BindingNotFoundError";
  }
};
var CircularDependencyError = class extends ContainerError {
  constructor(path) {
    super(`Circular dependency detected: ${path.join(" -> ")}`);
    this.name = "CircularDependencyError";
  }
};

// node_modules/@novadi/core/dist/autowire.js
var paramNameCache = /* @__PURE__ */ new WeakMap();
function extractParameterNames(constructor) {
  const cached = paramNameCache.get(constructor);
  if (cached) {
    return cached;
  }
  const fnStr = constructor.toString();
  const match = fnStr.match(/constructor\s*\(([^)]*)\)/) || fnStr.match(/^[^(]*\(([^)]*)\)/);
  if (!match || !match[1]) {
    return [];
  }
  const params = match[1].split(",").map((param) => param.trim()).filter((param) => param.length > 0).map((param) => {
    let name = param.split(/[:=]/)[0].trim();
    name = name.replace(/^((public|private|protected|readonly)\s+)+/, "");
    if (name.includes("{") || name.includes("[")) {
      return null;
    }
    return name;
  }).filter((name) => name !== null);
  paramNameCache.set(constructor, params);
  return params;
}
function resolveByMap(constructor, container, options) {
  if (!options.map) {
    throw new Error("AutoWire map strategy requires options.map to be defined");
  }
  const paramNames = extractParameterNames(constructor);
  const resolvedDeps = [];
  for (const paramName of paramNames) {
    const resolver = options.map[paramName];
    if (resolver === void 0) {
      if (options.strict) {
        throw new Error(`Cannot resolve parameter "${paramName}" on ${constructor.name}. Not found in autowire map. Add it to the map: .autoWire({ map: { ${paramName}: ... } })`);
      } else {
        resolvedDeps.push(void 0);
      }
      continue;
    }
    if (typeof resolver === "function") {
      resolvedDeps.push(resolver(container));
    } else {
      resolvedDeps.push(container.resolve(resolver));
    }
  }
  return resolvedDeps;
}
function resolveByMapResolvers(_constructor, container, options) {
  if (!options.mapResolvers || options.mapResolvers.length === 0) {
    return [];
  }
  const resolvedDeps = [];
  for (let i = 0; i < options.mapResolvers.length; i++) {
    const resolver = options.mapResolvers[i];
    if (resolver === void 0) {
      resolvedDeps.push(void 0);
    } else if (typeof resolver === "function") {
      resolvedDeps.push(resolver(container));
    } else {
      resolvedDeps.push(container.resolve(resolver));
    }
  }
  return resolvedDeps;
}
function autowire(constructor, container, options) {
  const opts = {
    by: "paramName",
    strict: false,
    ...options
  };
  if (opts.mapResolvers && opts.mapResolvers.length > 0) {
    return resolveByMapResolvers(constructor, container, opts);
  }
  if (opts.map && Object.keys(opts.map).length > 0) {
    return resolveByMap(constructor, container, opts);
  }
  return [];
}

// node_modules/@novadi/core/dist/builder.js
var RegistrationBuilder = class {
  constructor(pending, registrations) {
    this.registrations = registrations;
    this.configs = [];
    this.defaultLifetime = "singleton";
    this.pending = pending;
  }
  /**
   * Bind this registration to a token or interface type
   *
   * @overload
   * @param {Token<U>} token - Explicit token for binding
   *
   * @overload
   * @param {string} typeName - Interface type name (auto-generated by transformer)
   */
  as(tokenOrTypeName) {
    if (tokenOrTypeName && typeof tokenOrTypeName === "object" && "symbol" in tokenOrTypeName) {
      const config = {
        token: tokenOrTypeName,
        type: this.pending.type,
        value: this.pending.value,
        factory: this.pending.factory,
        constructor: this.pending.constructor,
        lifetime: this.defaultLifetime
      };
      this.configs.push(config);
      this.registrations.push(config);
      return this;
    } else {
      const config = {
        token: null,
        // Will be set during build()
        type: this.pending.type,
        value: this.pending.value,
        factory: this.pending.factory,
        constructor: this.pending.constructor,
        lifetime: this.defaultLifetime,
        interfaceType: tokenOrTypeName
      };
      this.configs.push(config);
      this.registrations.push(config);
      return this;
    }
  }
  /**
   * Register as default implementation for an interface
   * Combines as() + asDefault()
   */
  asDefaultInterface(typeName) {
    this.as("TInterface", typeName);
    return this.asDefault();
  }
  /**
   * Register as a keyed interface implementation
   * Combines as() + keyed()
   */
  asKeyedInterface(key, typeName) {
    this.as("TInterface", typeName);
    return this.keyed(key);
  }
  /**
   * Register as multiple implemented interfaces
   */
  asImplementedInterfaces(tokens) {
    if (tokens.length === 0) {
      return this;
    }
    if (this.configs.length > 0) {
      for (const config of this.configs) {
        config.lifetime = "singleton";
        config.additionalTokens = config.additionalTokens || [];
        config.additionalTokens.push(...tokens);
      }
      return this;
    }
    const firstConfig = {
      token: tokens[0],
      type: this.pending.type,
      value: this.pending.value,
      factory: this.pending.factory,
      constructor: this.pending.constructor,
      lifetime: "singleton"
    };
    this.configs.push(firstConfig);
    this.registrations.push(firstConfig);
    for (let i = 1; i < tokens.length; i++) {
      firstConfig.additionalTokens = firstConfig.additionalTokens || [];
      firstConfig.additionalTokens.push(tokens[i]);
    }
    return this;
  }
  /**
   * Set singleton lifetime (one instance for entire container)
   */
  singleInstance() {
    for (const config of this.configs) {
      config.lifetime = "singleton";
    }
    return this;
  }
  /**
   * Set per-request lifetime (one instance per resolve call tree)
   */
  instancePerRequest() {
    for (const config of this.configs) {
      config.lifetime = "per-request";
    }
    return this;
  }
  /**
   * Set transient lifetime (new instance every time)
   * Alias for default behavior
   */
  instancePerDependency() {
    for (const config of this.configs) {
      config.lifetime = "transient";
    }
    return this;
  }
  /**
   * Name this registration for named resolution
   */
  named(name) {
    for (const config of this.configs) {
      config.name = name;
    }
    return this;
  }
  /**
   * Key this registration for keyed resolution
   */
  keyed(key) {
    for (const config of this.configs) {
      config.key = key;
    }
    return this;
  }
  /**
   * Mark this as default registration
   * Default registrations don't override existing ones
   */
  asDefault() {
    for (const config of this.configs) {
      config.isDefault = true;
    }
    return this;
  }
  /**
   * Only register if token not already registered
   */
  ifNotRegistered() {
    for (const config of this.configs) {
      config.ifNotRegistered = true;
    }
    return this;
  }
  /**
   * Specify parameter values for constructor (primitives and constants)
   * Use this for non-DI parameters like strings, numbers, config values
   */
  withParameters(parameters) {
    for (const config of this.configs) {
      config.parameterValues = parameters;
    }
    return this;
  }
  /**
   * Enable automatic dependency injection (autowiring)
   * Supports three strategies: paramName (default), map, and class
   *
   * @example
   * ```ts
   * // Strategy 1: paramName (default, requires non-minified code in dev)
   * builder.registerType(EventBus).as<IEventBus>().autoWire()
   *
   * // Strategy 2: map (minify-safe, explicit)
   * builder.registerType(EventBus).as<IEventBus>().autoWire({
   *   map: {
   *     logger: (c) => c.resolveType<ILogger>()
   *   }
   * })
   *
   * // Strategy 3: class (requires build-time codegen)
   * builder.registerType(EventBus).as<IEventBus>().autoWire({ by: 'class' })
   * ```
   */
  autoWire(options) {
    for (const config of this.configs) {
      config.autowireOptions = options || { by: "paramName", strict: false };
    }
    return this;
  }
};
var Builder = class {
  constructor(baseContainer) {
    this.baseContainer = baseContainer;
    this.registrations = [];
  }
  /**
   * Register a class constructor
   */
  registerType(constructor) {
    const pending = {
      type: "type",
      value: null,
      constructor
    };
    return new RegistrationBuilder(pending, this.registrations);
  }
  /**
   * Register a pre-created instance
   */
  registerInstance(instance) {
    const pending = {
      type: "instance",
      value: instance,
      constructor: void 0
    };
    return new RegistrationBuilder(pending, this.registrations);
  }
  /**
   * Register a factory function
   */
  register(factory) {
    const pending = {
      type: "factory",
      value: null,
      factory,
      constructor: void 0
    };
    return new RegistrationBuilder(pending, this.registrations);
  }
  /**
   * Register a module (function that adds multiple registrations)
   */
  module(moduleFunc) {
    moduleFunc(this);
    return this;
  }
  /**
   * Resolve interface type names to tokens
   * @internal
   */
  resolveInterfaceTokens(container) {
    for (const config of this.registrations) {
      if (config.interfaceType !== void 0 && !config.token) {
        config.token = container.interfaceToken(config.interfaceType);
      }
    }
  }
  /**
   * Identify tokens that have non-default registrations
   * @internal
   */
  identifyNonDefaultTokens() {
    const tokensWithNonDefaults = /* @__PURE__ */ new Set();
    for (const config of this.registrations) {
      if (!config.isDefault && !config.name && config.key === void 0) {
        tokensWithNonDefaults.add(config.token);
      }
    }
    return tokensWithNonDefaults;
  }
  /**
   * Check if registration should be skipped
   * @internal
   */
  shouldSkipRegistration(config, tokensWithNonDefaults, registeredTokens) {
    if (config.isDefault && !config.name && config.key === void 0 && tokensWithNonDefaults.has(config.token)) {
      return true;
    }
    if (config.ifNotRegistered && registeredTokens.has(config.token)) {
      return true;
    }
    if (config.isDefault && registeredTokens.has(config.token)) {
      return true;
    }
    return false;
  }
  /**
   * Create binding token for registration (named, keyed, or multi)
   * @internal
   */
  createBindingToken(config, namedRegistrations, keyedRegistrations, multiRegistrations) {
    if (config.name) {
      const bindingToken = Token(`__named_${config.name}`);
      namedRegistrations.set(config.name, { ...config, token: bindingToken });
      return bindingToken;
    } else if (config.key !== void 0) {
      const keyStr = typeof config.key === "symbol" ? config.key.toString() : config.key;
      const bindingToken = Token(`__keyed_${keyStr}`);
      keyedRegistrations.set(config.key, { ...config, token: bindingToken });
      return bindingToken;
    } else {
      if (multiRegistrations.has(config.token)) {
        const bindingToken = Token(`__multi_${config.token.toString()}_${multiRegistrations.get(config.token).length}`);
        multiRegistrations.get(config.token).push(bindingToken);
        return bindingToken;
      } else {
        multiRegistrations.set(config.token, [config.token]);
        return config.token;
      }
    }
  }
  /**
   * Register additional interfaces for a config
   * @internal
   */
  registerAdditionalInterfaces(container, config, bindingToken, registeredTokens) {
    if (config.additionalTokens) {
      for (const additionalToken of config.additionalTokens) {
        container.bindFactory(additionalToken, (c) => c.resolve(bindingToken), { lifetime: config.lifetime });
        registeredTokens.add(additionalToken);
      }
    }
  }
  /**
   * Build the container with all registered bindings
   */
  build() {
    const container = this.baseContainer.createChild();
    this.resolveInterfaceTokens(container);
    const registeredTokens = /* @__PURE__ */ new Set();
    const namedRegistrations = /* @__PURE__ */ new Map();
    const keyedRegistrations = /* @__PURE__ */ new Map();
    const multiRegistrations = /* @__PURE__ */ new Map();
    const tokensWithNonDefaults = this.identifyNonDefaultTokens();
    for (const config of this.registrations) {
      if (this.shouldSkipRegistration(config, tokensWithNonDefaults, registeredTokens)) {
        continue;
      }
      const bindingToken = this.createBindingToken(config, namedRegistrations, keyedRegistrations, multiRegistrations);
      this.applyRegistration(container, { ...config, token: bindingToken });
      registeredTokens.add(config.token);
      this.registerAdditionalInterfaces(container, config, bindingToken, registeredTokens);
    }
    ;
    container.__namedRegistrations = namedRegistrations;
    container.__keyedRegistrations = keyedRegistrations;
    container.__multiRegistrations = multiRegistrations;
    return container;
  }
  /**
   * Analyze constructor to detect dependencies
   * @internal
   */
  analyzeConstructor(constructor) {
    const constructorStr = constructor.toString();
    const hasDependencies = /constructor\s*\([^)]+\)/.test(constructorStr);
    return { hasDependencies };
  }
  /**
   * Create optimized factory for zero-dependency constructors
   * @internal
   */
  createOptimizedFactory(container, config, options) {
    if (config.lifetime === "singleton") {
      const instance = new config.constructor();
      container.bindValue(config.token, instance);
    } else if (config.lifetime === "transient") {
      const ctor = config.constructor;
      const fastFactory = () => new ctor();
      container.fastTransientCache.set(config.token, fastFactory);
      container.bindFactory(config.token, fastFactory, options);
    } else {
      const factory = () => new config.constructor();
      container.bindFactory(config.token, factory, options);
    }
  }
  /**
   * Create autowire factory
   * @internal
   */
  createAutoWireFactory(container, config, options) {
    const factory = (c) => {
      const resolvedDeps = autowire(config.constructor, c, config.autowireOptions);
      return new config.constructor(...resolvedDeps);
    };
    container.bindFactory(config.token, factory, options);
  }
  /**
   * Create withParameters factory
   * @internal
   */
  createParameterFactory(container, config, options) {
    const factory = () => {
      const values = Object.values(config.parameterValues);
      return new config.constructor(...values);
    };
    container.bindFactory(config.token, factory, options);
  }
  /**
   * Apply type registration (class constructor)
   * @internal
   */
  applyTypeRegistration(container, config, options) {
    const { hasDependencies } = this.analyzeConstructor(config.constructor);
    if (!hasDependencies && !config.autowireOptions && !config.parameterValues) {
      this.createOptimizedFactory(container, config, options);
      return;
    }
    if (config.autowireOptions) {
      this.createAutoWireFactory(container, config, options);
      return;
    }
    if (config.parameterValues) {
      this.createParameterFactory(container, config, options);
      return;
    }
    if (hasDependencies) {
      const className = config.constructor.name || "UnnamedClass";
      throw new Error(`Service "${className}" has constructor dependencies but no autowiring configuration.

Solutions:
  1. \u2B50 Use the NovaDI transformer (recommended):
     - Add "@novadi/core/unplugin" to your build config
     - Transformer automatically generates .autoWire() for all dependencies

  2. Add manual autowiring:
     .autoWire({ map: { /* param: resolver */ } })

  3. Use a factory function:
     .register((c) => new ${className}(...))

See docs: https://github.com/janus007/NovaDI#autowire`);
    }
    const factory = () => new config.constructor();
    container.bindFactory(config.token, factory, options);
  }
  applyRegistration(container, config) {
    const options = { lifetime: config.lifetime };
    switch (config.type) {
      case "instance":
        container.bindValue(config.token, config.value);
        break;
      case "factory":
        container.bindFactory(config.token, config.factory, options);
        break;
      case "type":
        this.applyTypeRegistration(container, config, options);
        break;
    }
  }
};

// node_modules/@novadi/core/dist/container.js
function isDisposable(obj) {
  return obj && typeof obj.dispose === "function";
}
var ResolutionContext = class {
  constructor() {
    this.resolvingStack = /* @__PURE__ */ new Set();
    this.perRequestCache = /* @__PURE__ */ new Map();
  }
  isResolving(token2) {
    return this.resolvingStack.has(token2);
  }
  enterResolve(token2) {
    this.resolvingStack.add(token2);
  }
  exitResolve(token2) {
    this.resolvingStack.delete(token2);
    this.path = void 0;
  }
  getPath() {
    if (!this.path) {
      this.path = Array.from(this.resolvingStack).map((t) => t.toString());
    }
    return [...this.path];
  }
  cachePerRequest(token2, instance) {
    this.perRequestCache.set(token2, instance);
  }
  getPerRequest(token2) {
    return this.perRequestCache.get(token2);
  }
  hasPerRequest(token2) {
    return this.perRequestCache.has(token2);
  }
  /**
   * Reset context for reuse in object pool
   * Performance: Reusing contexts avoids heap allocations
   */
  reset() {
    this.resolvingStack.clear();
    this.perRequestCache.clear();
    this.path = void 0;
  }
};
var ResolutionContextPool = class {
  constructor() {
    this.pool = [];
    this.maxSize = 10;
  }
  acquire() {
    const context = this.pool.pop();
    if (context) {
      context.reset();
      return context;
    }
    return new ResolutionContext();
  }
  release(context) {
    if (this.pool.length < this.maxSize) {
      this.pool.push(context);
    }
  }
};
var Container = class _Container {
  constructor(parent) {
    this.bindings = /* @__PURE__ */ new Map();
    this.singletonCache = /* @__PURE__ */ new Map();
    this.singletonOrder = [];
    this.interfaceRegistry = /* @__PURE__ */ new Map();
    this.interfaceTokenCache = /* @__PURE__ */ new Map();
    this.fastTransientCache = /* @__PURE__ */ new Map();
    this.ultraFastSingletonCache = /* @__PURE__ */ new Map();
    this.parent = parent;
  }
  /**
   * Bind a pre-created value to a token
   */
  bindValue(token2, value) {
    this.bindings.set(token2, {
      type: "value",
      lifetime: "singleton",
      value,
      constructor: void 0
    });
    this.invalidateBindingCache();
  }
  /**
   * Bind a factory function to a token
   */
  bindFactory(token2, factory, options) {
    this.bindings.set(token2, {
      type: "factory",
      lifetime: options?.lifetime || "transient",
      factory,
      dependencies: options?.dependencies,
      constructor: void 0
    });
    this.invalidateBindingCache();
  }
  /**
   * Bind a class constructor to a token
   */
  bindClass(token2, constructor, options) {
    const binding = {
      type: "class",
      lifetime: options?.lifetime || "transient",
      constructor,
      dependencies: options?.dependencies
    };
    this.bindings.set(token2, binding);
    this.invalidateBindingCache();
    if (binding.lifetime === "transient" && (!binding.dependencies || binding.dependencies.length === 0)) {
      this.fastTransientCache.set(token2, () => new constructor());
    }
  }
  /**
   * Resolve a dependency synchronously
   * Performance optimized with multiple fast paths
   */
  resolve(token2) {
    const cached = this.tryGetFromCaches(token2);
    if (cached !== void 0) {
      return cached;
    }
    if (this.currentContext) {
      return this.resolveWithContext(token2, this.currentContext);
    }
    const context = _Container.contextPool.acquire();
    this.currentContext = context;
    try {
      return this.resolveWithContext(token2, context);
    } finally {
      this.currentContext = void 0;
      _Container.contextPool.release(context);
    }
  }
  /**
   * SPECIALIZED: Ultra-fast singleton resolve (no safety checks)
   * Use ONLY when you're 100% sure the token is a registered singleton
   * @internal For performance-critical paths only
   */
  resolveSingletonUnsafe(token2) {
    return this.ultraFastSingletonCache.get(token2) ?? this.singletonCache.get(token2);
  }
  /**
   * SPECIALIZED: Fast transient resolve for zero-dependency classes
   * Skips all context creation and circular dependency checks
   * @internal For performance-critical paths only
   */
  resolveTransientSimple(token2) {
    const factory = this.fastTransientCache.get(token2);
    if (factory) {
      return factory();
    }
    return this.resolve(token2);
  }
  /**
   * SPECIALIZED: Batch resolve multiple dependencies at once
   * More efficient than multiple individual resolves
   */
  resolveBatch(tokens) {
    const wasResolving = !!this.currentContext;
    const context = this.currentContext || _Container.contextPool.acquire();
    if (!wasResolving) {
      this.currentContext = context;
    }
    try {
      const results = tokens.map((token2) => {
        const cached = this.tryGetFromCaches(token2);
        if (cached !== void 0)
          return cached;
        return this.resolveWithContext(token2, context);
      });
      return results;
    } finally {
      if (!wasResolving) {
        this.currentContext = void 0;
        _Container.contextPool.release(context);
      }
    }
  }
  /**
   * Resolve a dependency asynchronously (supports async factories)
   */
  async resolveAsync(token2) {
    if (this.currentContext) {
      return this.resolveAsyncWithContext(token2, this.currentContext);
    }
    const context = _Container.contextPool.acquire();
    this.currentContext = context;
    try {
      return await this.resolveAsyncWithContext(token2, context);
    } finally {
      this.currentContext = void 0;
      _Container.contextPool.release(context);
    }
  }
  /**
   * Try to get instance from all cache levels
   * Returns undefined if not cached
   * @internal
   */
  tryGetFromCaches(token2) {
    const ultraFast = this.ultraFastSingletonCache.get(token2);
    if (ultraFast !== void 0) {
      return ultraFast;
    }
    if (this.singletonCache.has(token2)) {
      const cached = this.singletonCache.get(token2);
      this.ultraFastSingletonCache.set(token2, cached);
      return cached;
    }
    const fastFactory = this.fastTransientCache.get(token2);
    if (fastFactory) {
      return fastFactory();
    }
    return void 0;
  }
  /**
   * Cache instance based on lifetime strategy
   * @internal
   */
  cacheInstance(token2, instance, lifetime, context) {
    if (lifetime === "singleton") {
      this.singletonCache.set(token2, instance);
      this.singletonOrder.push(token2);
      this.ultraFastSingletonCache.set(token2, instance);
    } else if (lifetime === "per-request" && context) {
      context.cachePerRequest(token2, instance);
    }
  }
  /**
   * Validate and get binding with circular dependency check
   * Returns binding or throws error
   * @internal
   */
  validateAndGetBinding(token2, context) {
    if (context.isResolving(token2)) {
      throw new CircularDependencyError([...context.getPath(), token2.toString()]);
    }
    const binding = this.getBinding(token2);
    if (!binding) {
      throw new BindingNotFoundError(token2.toString(), context.getPath());
    }
    return binding;
  }
  /**
   * Instantiate from binding synchronously
   * @internal
   */
  instantiateBindingSync(binding, token2, context) {
    switch (binding.type) {
      case "value":
        return binding.value;
      case "factory":
        const result = binding.factory(this);
        if (result instanceof Promise) {
          throw new Error(`Async factory detected for ${token2.toString()}. Use resolveAsync() instead.`);
        }
        return result;
      case "class":
        const deps = binding.dependencies || [];
        const resolvedDeps = deps.map((dep) => this.resolveWithContext(dep, context));
        return new binding.constructor(...resolvedDeps);
      case "inline-class":
        return new binding.constructor();
      default:
        throw new Error(`Unknown binding type: ${binding.type}`);
    }
  }
  /**
   * Instantiate from binding asynchronously
   * @internal
   */
  async instantiateBindingAsync(binding, context) {
    switch (binding.type) {
      case "value":
        return binding.value;
      case "factory":
        return await Promise.resolve(binding.factory(this));
      case "class":
        const deps = binding.dependencies || [];
        const resolvedDeps = await Promise.all(deps.map((dep) => this.resolveAsyncWithContext(dep, context)));
        return new binding.constructor(...resolvedDeps);
      case "inline-class":
        return new binding.constructor();
      default:
        throw new Error(`Unknown binding type: ${binding.type}`);
    }
  }
  /**
   * Create a child container that inherits bindings from this container
   */
  createChild() {
    return new _Container(this);
  }
  /**
   * Dispose all singleton instances in reverse registration order
   */
  async dispose() {
    const errors = [];
    for (let i = this.singletonOrder.length - 1; i >= 0; i--) {
      const token2 = this.singletonOrder[i];
      const instance = this.singletonCache.get(token2);
      if (instance && isDisposable(instance)) {
        try {
          await instance.dispose();
        } catch (error) {
          errors.push(error);
        }
      }
    }
    this.singletonCache.clear();
    this.singletonOrder.length = 0;
  }
  /**
   * Create a fluent builder for registering dependencies
   */
  builder() {
    return new Builder(this);
  }
  /**
   * Resolve a named service
   */
  resolveNamed(name) {
    const namedRegistrations = this.__namedRegistrations;
    if (!namedRegistrations) {
      throw new Error(`Named service "${name}" not found. No named registrations exist.`);
    }
    const config = namedRegistrations.get(name);
    if (!config) {
      throw new Error(`Named service "${name}" not found`);
    }
    return this.resolve(config.token);
  }
  /**
   * Resolve a keyed service
   */
  resolveKeyed(key) {
    const keyedRegistrations = this.__keyedRegistrations;
    if (!keyedRegistrations) {
      throw new Error(`Keyed service not found. No keyed registrations exist.`);
    }
    const config = keyedRegistrations.get(key);
    if (!config) {
      const keyStr = typeof key === "symbol" ? key.toString() : `"${key}"`;
      throw new Error(`Keyed service ${keyStr} not found`);
    }
    return this.resolve(config.token);
  }
  /**
   * Resolve all registrations for a token
   */
  resolveAll(token2) {
    const multiRegistrations = this.__multiRegistrations;
    if (!multiRegistrations) {
      return [];
    }
    const tokens = multiRegistrations.get(token2);
    if (!tokens || tokens.length === 0) {
      return [];
    }
    return tokens.map((t) => this.resolve(t));
  }
  /**
   * Get registry information for debugging/visualization
   * Returns array of binding information
   */
  getRegistry() {
    const registry = [];
    this.bindings.forEach((binding, token2) => {
      registry.push({
        token: token2.description || token2.symbol.toString(),
        type: binding.type,
        lifetime: binding.lifetime,
        dependencies: binding.dependencies?.map((d) => d.description || d.symbol.toString())
      });
    });
    return registry;
  }
  /**
   * Get or create a token for an interface type
   * Uses a type name hash as key for the interface registry
   */
  interfaceToken(typeName) {
    const key = typeName || `Interface_${Math.random().toString(36).substr(2, 9)}`;
    if (this.interfaceRegistry.has(key)) {
      return this.interfaceRegistry.get(key);
    }
    if (this.parent) {
      const parentToken = this.parent.interfaceToken(key);
      return parentToken;
    }
    const token2 = Token(key);
    this.interfaceRegistry.set(key, token2);
    return token2;
  }
  /**
   * Resolve a dependency by interface type without explicit token
   */
  resolveType(typeName) {
    const key = typeName || "";
    let token2 = this.interfaceTokenCache.get(key);
    if (!token2) {
      token2 = this.interfaceToken(typeName);
      this.interfaceTokenCache.set(key, token2);
    }
    return this.resolve(token2);
  }
  /**
   * Resolve a keyed interface
   */
  resolveTypeKeyed(key, _typeName) {
    return this.resolveKeyed(key);
  }
  /**
   * Resolve all registrations for an interface type
   */
  resolveTypeAll(typeName) {
    const token2 = this.interfaceToken(typeName);
    return this.resolveAll(token2);
  }
  /**
   * Internal: Resolve with context for circular dependency detection
   */
  resolveWithContext(token2, context) {
    const binding = this.validateAndGetBinding(token2, context);
    if (binding.lifetime === "per-request" && context.hasPerRequest(token2)) {
      return context.getPerRequest(token2);
    }
    if (binding.lifetime === "singleton" && this.singletonCache.has(token2)) {
      return this.singletonCache.get(token2);
    }
    context.enterResolve(token2);
    try {
      const instance = this.instantiateBindingSync(binding, token2, context);
      this.cacheInstance(token2, instance, binding.lifetime, context);
      return instance;
    } finally {
      context.exitResolve(token2);
    }
  }
  /**
   * Internal: Async resolve with context
   */
  async resolveAsyncWithContext(token2, context) {
    const binding = this.validateAndGetBinding(token2, context);
    if (binding.lifetime === "per-request" && context.hasPerRequest(token2)) {
      return context.getPerRequest(token2);
    }
    if (binding.lifetime === "singleton" && this.singletonCache.has(token2)) {
      return this.singletonCache.get(token2);
    }
    context.enterResolve(token2);
    try {
      const instance = await this.instantiateBindingAsync(binding, context);
      this.cacheInstance(token2, instance, binding.lifetime, context);
      return instance;
    } finally {
      context.exitResolve(token2);
    }
  }
  /**
   * Get binding from this container or parent chain
   * Performance optimized: Uses flat cache to avoid recursive parent lookups
   */
  getBinding(token2) {
    if (!this.bindingCache) {
      this.buildBindingCache();
    }
    return this.bindingCache.get(token2);
  }
  /**
   * Build flat cache of all bindings including parent chain
   * This converts O(n) parent chain traversal to O(1) lookup
   */
  buildBindingCache() {
    this.bindingCache = /* @__PURE__ */ new Map();
    let current = this;
    while (current) {
      current.bindings.forEach((binding, token2) => {
        if (!this.bindingCache.has(token2)) {
          this.bindingCache.set(token2, binding);
        }
      });
      current = current.parent;
    }
  }
  /**
   * Invalidate binding cache when new bindings are added
   * Called by bindValue, bindFactory, bindClass
   */
  invalidateBindingCache() {
    this.bindingCache = void 0;
    this.ultraFastSingletonCache.clear();
  }
};
Container.contextPool = new ResolutionContextPool();

// node_modules/calendar/dist/chunk-OPIZ4QQE.js
var BaseGroupingRenderer = class {
  /**
   * Main render method - handles common logic
   */
  async render(context) {
    const allowedIds = context.filter[this.type] || [];
    if (allowedIds.length === 0)
      return;
    const entities = await this.getEntities(allowedIds);
    const dateCount = context.filter["date"]?.length || 1;
    const childIds = context.childType ? context.filter[context.childType] || [] : [];
    for (const entity of entities) {
      const entityChildIds = context.parentChildMap?.[entity.id] || [];
      const childCount = entityChildIds.filter((id) => childIds.includes(id)).length;
      const colspan = childCount * dateCount;
      const header = document.createElement(this.config.elementTag);
      header.dataset[this.config.idAttribute] = entity.id;
      header.style.setProperty(this.config.colspanVar, String(colspan));
      this.renderHeader(entity, header, context);
      context.headerContainer.appendChild(header);
    }
  }
  /**
   * Override this method for custom header rendering
   * Default: just sets textContent to display name
   */
  renderHeader(entity, header, _context) {
    header.textContent = this.getDisplayName(entity);
  }
  /**
   * Helper to render a single entity header.
   * Can be used by subclasses that override render() but want consistent header creation.
   */
  createHeader(entity, context) {
    const header = document.createElement(this.config.elementTag);
    header.dataset[this.config.idAttribute] = entity.id;
    this.renderHeader(entity, header, context);
    return header;
  }
};

// node_modules/calendar/dist/chunk-CMOI3H5F.js
var CoreEvents = {
  // Lifecycle events
  INITIALIZED: "core:initialized",
  READY: "core:ready",
  DESTROYED: "core:destroyed",
  // View events
  VIEW_CHANGED: "view:changed",
  VIEW_RENDERED: "view:rendered",
  // Navigation events
  DATE_CHANGED: "nav:date-changed",
  NAVIGATION_COMPLETED: "nav:navigation-completed",
  // Data events
  DATA_LOADING: "data:loading",
  DATA_LOADED: "data:loaded",
  DATA_ERROR: "data:error",
  // Grid events
  GRID_RENDERED: "grid:rendered",
  GRID_CLICKED: "grid:clicked",
  // Event management
  EVENT_CREATED: "event:created",
  EVENT_UPDATED: "event:updated",
  EVENT_DELETED: "event:deleted",
  EVENT_SELECTED: "event:selected",
  // Event drag-drop
  EVENT_DRAG_START: "event:drag-start",
  EVENT_DRAG_MOVE: "event:drag-move",
  EVENT_DRAG_END: "event:drag-end",
  EVENT_DRAG_CANCEL: "event:drag-cancel",
  EVENT_DRAG_COLUMN_CHANGE: "event:drag-column-change",
  // Header drag (timed → header conversion)
  EVENT_DRAG_ENTER_HEADER: "event:drag-enter-header",
  EVENT_DRAG_MOVE_HEADER: "event:drag-move-header",
  EVENT_DRAG_LEAVE_HEADER: "event:drag-leave-header",
  // Event resize
  EVENT_RESIZE_START: "event:resize-start",
  EVENT_RESIZE_END: "event:resize-end",
  // Edge scroll
  EDGE_SCROLL_TICK: "edge-scroll:tick",
  EDGE_SCROLL_STARTED: "edge-scroll:started",
  EDGE_SCROLL_STOPPED: "edge-scroll:stopped",
  // System events
  ERROR: "system:error",
  // Sync events
  SYNC_STARTED: "sync:started",
  SYNC_COMPLETED: "sync:completed",
  SYNC_FAILED: "sync:failed",
  // Entity events - for audit and sync
  ENTITY_SAVED: "entity:saved",
  ENTITY_DELETED: "entity:deleted",
  // Audit events
  AUDIT_LOGGED: "audit:logged",
  // Rendering events
  EVENTS_RENDERED: "events:rendered"
};
var SyncPlugin = class {
  constructor(service) {
    this.service = service;
  }
  /**
   * Mark entity as successfully synced
   */
  async markAsSynced(id) {
    const entity = await this.service.get(id);
    if (entity) {
      entity.syncStatus = "synced";
      await this.service.save(entity);
    }
  }
  /**
   * Mark entity as sync error
   */
  async markAsError(id) {
    const entity = await this.service.get(id);
    if (entity) {
      entity.syncStatus = "error";
      await this.service.save(entity);
    }
  }
  /**
   * Get current sync status for an entity
   */
  async getSyncStatus(id) {
    const entity = await this.service.get(id);
    return entity ? entity.syncStatus : null;
  }
  /**
   * Get entities by sync status using IndexedDB index
   */
  async getBySyncStatus(syncStatus) {
    return new Promise((resolve, reject) => {
      const transaction = this.service.db.transaction([this.service.storeName], "readonly");
      const store = transaction.objectStore(this.service.storeName);
      const index = store.index("syncStatus");
      const request = index.getAll(syncStatus);
      request.onsuccess = () => {
        const data = request.result;
        const entities = data.map((item) => this.service.deserialize(item));
        resolve(entities);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get by sync status ${syncStatus}: ${request.error}`));
      };
    });
  }
};
function arrayDifference(first, second) {
  const secondSet = new Set(second);
  return first.filter((item) => !secondSet.has(item));
}
function arrayIntersection(first, second) {
  const secondSet = new Set(second);
  return first.filter((item) => secondSet.has(item));
}
function keyBy(arr, getKey2) {
  const result = {};
  for (const item of arr) {
    result[String(getKey2(item))] = item;
  }
  return result;
}
function diff(oldObj, newObj, options = {}) {
  let { embeddedObjKeys } = options;
  const { keysToSkip, treatTypeChangeAsReplace } = options;
  if (embeddedObjKeys instanceof Map) {
    embeddedObjKeys = new Map(
      Array.from(embeddedObjKeys.entries()).map(([key, value]) => [
        key instanceof RegExp ? key : key.replace(/^\./, ""),
        value
      ])
    );
  } else if (embeddedObjKeys) {
    embeddedObjKeys = Object.fromEntries(
      Object.entries(embeddedObjKeys).map(([key, value]) => [key.replace(/^\./, ""), value])
    );
  }
  return compare(oldObj, newObj, [], [], {
    embeddedObjKeys,
    keysToSkip: keysToSkip ?? [],
    treatTypeChangeAsReplace: treatTypeChangeAsReplace ?? true
  });
}
var getTypeOfObj = (obj) => {
  if (typeof obj === "undefined") {
    return "undefined";
  }
  if (obj === null) {
    return null;
  }
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
};
var getKey = (path) => {
  const left = path[path.length - 1];
  return left != null ? left : "$root";
};
var compare = (oldObj, newObj, path, keyPath, options) => {
  let changes = [];
  const currentPath = keyPath.join(".");
  if (options.keysToSkip?.some((skipPath) => {
    if (currentPath === skipPath) {
      return true;
    }
    if (skipPath.includes(".") && skipPath.startsWith(currentPath + ".")) {
      return false;
    }
    if (skipPath.includes(".")) {
      const skipParts = skipPath.split(".");
      const currentParts = currentPath.split(".");
      if (currentParts.length >= skipParts.length) {
        for (let i = 0; i < skipParts.length; i++) {
          if (skipParts[i] !== currentParts[i]) {
            return false;
          }
        }
        return true;
      }
    }
    return false;
  })) {
    return changes;
  }
  const typeOfOldObj = getTypeOfObj(oldObj);
  const typeOfNewObj = getTypeOfObj(newObj);
  if (options.treatTypeChangeAsReplace && typeOfOldObj !== typeOfNewObj) {
    if (typeOfOldObj !== "undefined") {
      changes.push({ type: "REMOVE", key: getKey(path), value: oldObj });
    }
    if (typeOfNewObj !== "undefined") {
      changes.push({ type: "ADD", key: getKey(path), value: newObj });
    }
    return changes;
  }
  if (typeOfNewObj === "undefined" && typeOfOldObj !== "undefined") {
    changes.push({ type: "REMOVE", key: getKey(path), value: oldObj });
    return changes;
  }
  if (typeOfNewObj === "Object" && typeOfOldObj === "Array") {
    changes.push({ type: "UPDATE", key: getKey(path), value: newObj, oldValue: oldObj });
    return changes;
  }
  if (typeOfNewObj === null) {
    if (typeOfOldObj !== null) {
      changes.push({ type: "UPDATE", key: getKey(path), value: newObj, oldValue: oldObj });
    }
    return changes;
  }
  switch (typeOfOldObj) {
    case "Date":
      if (typeOfNewObj === "Date") {
        changes = changes.concat(
          comparePrimitives(oldObj.getTime(), newObj.getTime(), path).map((x) => ({
            ...x,
            value: new Date(x.value),
            oldValue: new Date(x.oldValue)
          }))
        );
      } else {
        changes = changes.concat(comparePrimitives(oldObj, newObj, path));
      }
      break;
    case "Object": {
      const diffs = compareObject(oldObj, newObj, path, keyPath, false, options);
      if (diffs.length) {
        if (path.length) {
          changes.push({
            type: "UPDATE",
            key: getKey(path),
            changes: diffs
          });
        } else {
          changes = changes.concat(diffs);
        }
      }
      break;
    }
    case "Array":
      changes = changes.concat(compareArray(oldObj, newObj, path, keyPath, options));
      break;
    case "Function":
      break;
    default:
      changes = changes.concat(comparePrimitives(oldObj, newObj, path));
  }
  return changes;
};
var compareObject = (oldObj, newObj, path, keyPath, skipPath = false, options = {}) => {
  let k;
  let newKeyPath;
  let newPath;
  if (skipPath == null) {
    skipPath = false;
  }
  let changes = [];
  const oldObjKeys = Object.keys(oldObj);
  const newObjKeys = Object.keys(newObj);
  const intersectionKeys = arrayIntersection(oldObjKeys, newObjKeys);
  for (k of intersectionKeys) {
    newPath = path.concat([k]);
    newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
    const diffs = compare(oldObj[k], newObj[k], newPath, newKeyPath, options);
    if (diffs.length) {
      changes = changes.concat(diffs);
    }
  }
  const addedKeys = arrayDifference(newObjKeys, oldObjKeys);
  for (k of addedKeys) {
    newPath = path.concat([k]);
    newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
    const currentPath = newKeyPath.join(".");
    if (options.keysToSkip?.some((skipPath2) => currentPath === skipPath2 || currentPath.startsWith(skipPath2 + "."))) {
      continue;
    }
    changes.push({
      type: "ADD",
      key: getKey(newPath),
      value: newObj[k]
    });
  }
  const deletedKeys = arrayDifference(oldObjKeys, newObjKeys);
  for (k of deletedKeys) {
    newPath = path.concat([k]);
    newKeyPath = skipPath ? keyPath : keyPath.concat([k]);
    const currentPath = newKeyPath.join(".");
    if (options.keysToSkip?.some((skipPath2) => currentPath === skipPath2 || currentPath.startsWith(skipPath2 + "."))) {
      continue;
    }
    changes.push({
      type: "REMOVE",
      key: getKey(newPath),
      value: oldObj[k]
    });
  }
  return changes;
};
var compareArray = (oldObj, newObj, path, keyPath, options) => {
  if (getTypeOfObj(newObj) !== "Array") {
    return [{ type: "UPDATE", key: getKey(path), value: newObj, oldValue: oldObj }];
  }
  const left = getObjectKey(options.embeddedObjKeys, keyPath);
  const uniqKey = left != null ? left : "$index";
  const indexedOldObj = convertArrayToObj(oldObj, uniqKey);
  const indexedNewObj = convertArrayToObj(newObj, uniqKey);
  const diffs = compareObject(indexedOldObj, indexedNewObj, path, keyPath, true, options);
  if (diffs.length) {
    return [
      {
        type: "UPDATE",
        key: getKey(path),
        embeddedKey: typeof uniqKey === "function" && uniqKey.length === 2 ? uniqKey(newObj[0], true) : uniqKey,
        changes: diffs
      }
    ];
  } else {
    return [];
  }
};
var getObjectKey = (embeddedObjKeys, keyPath) => {
  if (embeddedObjKeys != null) {
    const path = keyPath.join(".");
    if (embeddedObjKeys instanceof Map) {
      for (const [key2, value] of embeddedObjKeys.entries()) {
        if (key2 instanceof RegExp) {
          if (path.match(key2)) {
            return value;
          }
        } else if (path === key2) {
          return value;
        }
      }
    }
    const key = embeddedObjKeys[path];
    if (key != null) {
      return key;
    }
  }
  return void 0;
};
var convertArrayToObj = (arr, uniqKey) => {
  let obj = {};
  if (uniqKey === "$value") {
    arr.forEach((value) => {
      obj[value] = value;
    });
  } else if (uniqKey !== "$index") {
    const keyFunction = typeof uniqKey === "string" ? (item) => item[uniqKey] : uniqKey;
    obj = keyBy(arr, keyFunction);
  } else {
    for (let i = 0; i < arr.length; i++) {
      const value = arr[i];
      obj[i] = value;
    }
  }
  return obj;
};
var comparePrimitives = (oldObj, newObj, path) => {
  const changes = [];
  if (oldObj !== newObj) {
    changes.push({
      type: "UPDATE",
      key: getKey(path),
      value: newObj,
      oldValue: oldObj
    });
  }
  return changes;
};
var BaseEntityService = class {
  constructor(context, eventBus) {
    this.context = context;
    this.eventBus = eventBus;
    this.syncPlugin = new SyncPlugin(this);
  }
  get db() {
    return this.context.getDatabase();
  }
  /**
   * Serialize entity before storing in IndexedDB
   */
  serialize(entity) {
    return entity;
  }
  /**
   * Deserialize data from IndexedDB back to entity
   */
  deserialize(data) {
    return data;
  }
  /**
   * Get a single entity by ID
   */
  async get(id) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readonly");
      const store = transaction.objectStore(this.storeName);
      const request = store.get(id);
      request.onsuccess = () => {
        const data = request.result;
        resolve(data ? this.deserialize(data) : null);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get ${this.entityType} ${id}: ${request.error}`));
      };
    });
  }
  /**
   * Get all entities
   */
  async getAll() {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readonly");
      const store = transaction.objectStore(this.storeName);
      const request = store.getAll();
      request.onsuccess = () => {
        const data = request.result;
        const entities = data.map((item) => this.deserialize(item));
        resolve(entities);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get all ${this.entityType}s: ${request.error}`));
      };
    });
  }
  /**
   * Save an entity (create or update)
   * Emits ENTITY_SAVED event with operation type and changes (diff for updates)
   * @param entity - Entity to save
   * @param silent - If true, skip event emission (used for seeding)
   */
  async save(entity, silent = false) {
    const entityId = entity.id;
    const existingEntity = await this.get(entityId);
    const isCreate = existingEntity === null;
    let changes;
    if (isCreate) {
      changes = entity;
    } else {
      const existingSerialized = this.serialize(existingEntity);
      const newSerialized = this.serialize(entity);
      changes = diff(existingSerialized, newSerialized);
    }
    const serialized = this.serialize(entity);
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readwrite");
      const store = transaction.objectStore(this.storeName);
      const request = store.put(serialized);
      request.onsuccess = () => {
        if (!silent) {
          const payload = {
            entityType: this.entityType,
            entityId,
            operation: isCreate ? "create" : "update",
            changes,
            timestamp: Date.now()
          };
          this.eventBus.emit(CoreEvents.ENTITY_SAVED, payload);
        }
        resolve();
      };
      request.onerror = () => {
        reject(new Error(`Failed to save ${this.entityType} ${entityId}: ${request.error}`));
      };
    });
  }
  /**
   * Delete an entity
   * Emits ENTITY_DELETED event
   */
  async delete(id) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readwrite");
      const store = transaction.objectStore(this.storeName);
      const request = store.delete(id);
      request.onsuccess = () => {
        const payload = {
          entityType: this.entityType,
          entityId: id,
          operation: "delete",
          timestamp: Date.now()
        };
        this.eventBus.emit(CoreEvents.ENTITY_DELETED, payload);
        resolve();
      };
      request.onerror = () => {
        reject(new Error(`Failed to delete ${this.entityType} ${id}: ${request.error}`));
      };
    });
  }
  // Sync methods - delegate to SyncPlugin
  async markAsSynced(id) {
    return this.syncPlugin.markAsSynced(id);
  }
  async markAsError(id) {
    return this.syncPlugin.markAsError(id);
  }
  async getSyncStatus(id) {
    return this.syncPlugin.getSyncStatus(id);
  }
  async getBySyncStatus(syncStatus) {
    return this.syncPlugin.getBySyncStatus(syncStatus);
  }
};

// node_modules/calendar/dist/index.js
var import_dayjs = __toESM(require_dayjs_min(), 1);
var import_utc = __toESM(require_utc(), 1);
var import_timezone = __toESM(require_timezone(), 1);
var import_isoWeek = __toESM(require_isoWeek(), 1);
var NavigationAnimator = class {
  constructor(headerTrack, contentTrack, headerDrawer) {
    this.headerTrack = headerTrack;
    this.contentTrack = contentTrack;
    this.headerDrawer = headerDrawer;
  }
  async slide(direction, renderFn) {
    const out = direction === "left" ? "-100%" : "100%";
    const into = direction === "left" ? "100%" : "-100%";
    await this.animateOut(out);
    await renderFn();
    await this.animateIn(into);
  }
  async animateOut(translate) {
    const animations = [
      this.headerTrack.animate([{ transform: "translateX(0)" }, { transform: `translateX(${translate})` }], { duration: 200, easing: "ease-in" }).finished,
      this.contentTrack.animate([{ transform: "translateX(0)" }, { transform: `translateX(${translate})` }], { duration: 200, easing: "ease-in" }).finished
    ];
    if (this.headerDrawer) {
      animations.push(this.headerDrawer.animate([{ transform: "translateX(0)" }, { transform: `translateX(${translate})` }], { duration: 200, easing: "ease-in" }).finished);
    }
    await Promise.all(animations);
  }
  async animateIn(translate) {
    const animations = [
      this.headerTrack.animate([{ transform: `translateX(${translate})` }, { transform: "translateX(0)" }], { duration: 200, easing: "ease-out" }).finished,
      this.contentTrack.animate([{ transform: `translateX(${translate})` }, { transform: "translateX(0)" }], { duration: 200, easing: "ease-out" }).finished
    ];
    if (this.headerDrawer) {
      animations.push(this.headerDrawer.animate([{ transform: `translateX(${translate})` }, { transform: "translateX(0)" }], { duration: 200, easing: "ease-out" }).finished);
    }
    await Promise.all(animations);
  }
};
var CalendarEvents = {
  // Command events (host → calendar)
  CMD_NAVIGATE_PREV: "calendar:cmd:navigate:prev",
  CMD_NAVIGATE_NEXT: "calendar:cmd:navigate:next",
  CMD_DRAWER_TOGGLE: "calendar:cmd:drawer:toggle",
  CMD_RENDER: "calendar:cmd:render",
  CMD_WORKWEEK_CHANGE: "calendar:cmd:workweek:change",
  CMD_VIEW_UPDATE: "calendar:cmd:view:update"
};
var CalendarApp = class {
  constructor(orchestrator, timeAxisRenderer, dateService, scrollManager, headerDrawerManager, dragDropManager, edgeScrollManager, resizeManager, headerDrawerRenderer, eventPersistenceManager, settingsService, viewConfigService, eventBus) {
    this.orchestrator = orchestrator;
    this.timeAxisRenderer = timeAxisRenderer;
    this.dateService = dateService;
    this.scrollManager = scrollManager;
    this.headerDrawerManager = headerDrawerManager;
    this.dragDropManager = dragDropManager;
    this.edgeScrollManager = edgeScrollManager;
    this.resizeManager = resizeManager;
    this.headerDrawerRenderer = headerDrawerRenderer;
    this.eventPersistenceManager = eventPersistenceManager;
    this.settingsService = settingsService;
    this.viewConfigService = viewConfigService;
    this.eventBus = eventBus;
    this.dayOffset = 0;
    this.currentViewId = "simple";
    this.workweekPreset = null;
    this.groupingOverrides = /* @__PURE__ */ new Map();
  }
  async init(container) {
    this.container = container;
    const gridSettings = await this.settingsService.getGridSettings();
    if (!gridSettings) {
      throw new Error("GridSettings not found");
    }
    this.workweekPreset = await this.settingsService.getDefaultWorkweekPreset();
    this.animator = new NavigationAnimator(container.querySelector("swp-header-track"), container.querySelector("swp-content-track"), container.querySelector("swp-header-drawer"));
    this.timeAxisRenderer.render(container.querySelector("#time-axis"), gridSettings.dayStartHour, gridSettings.dayEndHour);
    this.scrollManager.init(container);
    this.headerDrawerManager.init(container);
    this.dragDropManager.init(container);
    this.resizeManager.init(container);
    const scrollableContent = container.querySelector("swp-scrollable-content");
    this.edgeScrollManager.init(scrollableContent);
    this.setupEventListeners();
    this.emitStatus("ready");
  }
  setupEventListeners() {
    this.eventBus.on(CalendarEvents.CMD_NAVIGATE_PREV, () => {
      this.handleNavigatePrev();
    });
    this.eventBus.on(CalendarEvents.CMD_NAVIGATE_NEXT, () => {
      this.handleNavigateNext();
    });
    this.eventBus.on(CalendarEvents.CMD_DRAWER_TOGGLE, () => {
      this.headerDrawerManager.toggle();
    });
    this.eventBus.on(CalendarEvents.CMD_RENDER, (e) => {
      const { viewId } = e.detail;
      this.handleRenderCommand(viewId);
    });
    this.eventBus.on(CalendarEvents.CMD_WORKWEEK_CHANGE, (e) => {
      const { presetId } = e.detail;
      this.handleWorkweekChange(presetId);
    });
    this.eventBus.on(CalendarEvents.CMD_VIEW_UPDATE, (e) => {
      const { type, values } = e.detail;
      this.handleViewUpdate(type, values);
    });
  }
  async handleRenderCommand(viewId) {
    this.currentViewId = viewId;
    await this.render();
    this.emitStatus("rendered", { viewId });
  }
  async handleNavigatePrev() {
    const step = this.workweekPreset?.periodDays ?? 7;
    this.dayOffset -= step;
    await this.animator.slide("right", () => this.render());
    this.emitStatus("rendered", { viewId: this.currentViewId });
  }
  async handleNavigateNext() {
    const step = this.workweekPreset?.periodDays ?? 7;
    this.dayOffset += step;
    await this.animator.slide("left", () => this.render());
    this.emitStatus("rendered", { viewId: this.currentViewId });
  }
  async handleWorkweekChange(presetId) {
    const preset = await this.settingsService.getWorkweekPreset(presetId);
    if (preset) {
      this.workweekPreset = preset;
      await this.render();
      this.emitStatus("rendered", { viewId: this.currentViewId });
    }
  }
  async handleViewUpdate(type, values) {
    this.groupingOverrides.set(type, values);
    await this.render();
    this.emitStatus("rendered", { viewId: this.currentViewId });
  }
  async render() {
    const storedConfig = await this.viewConfigService.getById(this.currentViewId);
    if (!storedConfig) {
      this.emitStatus("error", { message: `ViewConfig not found: ${this.currentViewId}` });
      return;
    }
    const workDays = this.workweekPreset?.workDays || [1, 2, 3, 4, 5];
    const periodDays = this.workweekPreset?.periodDays ?? 7;
    const dates = periodDays === 1 ? this.dateService.getDatesFromOffset(this.dayOffset, workDays.length) : this.dateService.getWorkDaysFromOffset(this.dayOffset, workDays);
    const viewConfig = {
      ...storedConfig,
      groupings: storedConfig.groupings.map((g) => {
        if (g.type === "date") {
          return { ...g, values: dates };
        }
        const override = this.groupingOverrides.get(g.type);
        if (override) {
          return { ...g, values: override };
        }
        return g;
      })
    };
    await this.orchestrator.render(viewConfig, this.container);
  }
  emitStatus(status, detail) {
    this.container.dispatchEvent(new CustomEvent(`calendar:status:${status}`, {
      detail,
      bubbles: true
    }));
  }
};
function buildPipeline(renderers) {
  return {
    async run(context) {
      for (const renderer of renderers) {
        await renderer.render(context);
      }
    }
  };
}
var FilterTemplate = class {
  constructor(dateService, entityResolver) {
    this.dateService = dateService;
    this.entityResolver = entityResolver;
    this.fields = [];
  }
  /**
   * Tilføj felt til template
   * @param idProperty - Property-navn (bruges på både event og column.dataset)
   * @param derivedFrom - Hvis feltet udledes fra anden property (f.eks. date fra start)
   */
  addField(idProperty, derivedFrom) {
    this.fields.push({ idProperty, derivedFrom });
    return this;
  }
  /**
   * Parse dot-notation string into components
   * @example 'resource.teamId' → { entityType: 'resource', property: 'teamId', foreignKey: 'resourceId' }
   */
  parseDotNotation(idProperty) {
    if (!idProperty.includes("."))
      return null;
    const [entityType, property] = idProperty.split(".");
    return {
      entityType,
      property,
      foreignKey: entityType + "Id"
      // Convention: resource → resourceId
    };
  }
  /**
   * Get dataset key for column lookup
   * For dot-notation 'resource.teamId', we look for 'teamId' in dataset
   */
  getDatasetKey(idProperty) {
    const dotNotation = this.parseDotNotation(idProperty);
    if (dotNotation) {
      return dotNotation.property;
    }
    return idProperty;
  }
  /**
   * Byg nøgle fra kolonne
   * Læser værdier fra column.dataset[idProperty]
   * For dot-notation, uses the property part (resource.teamId → teamId)
   */
  buildKeyFromColumn(column) {
    return this.fields.map((f) => {
      const key = this.getDatasetKey(f.idProperty);
      return column.dataset[key] || "";
    }).join(":");
  }
  /**
   * Byg nøgle fra event
   * Læser værdier fra event[idProperty] eller udleder fra derivedFrom
   * For dot-notation, resolves via EntityResolver
   */
  buildKeyFromEvent(event) {
    const eventRecord = event;
    return this.fields.map((f) => {
      const dotNotation = this.parseDotNotation(f.idProperty);
      if (dotNotation) {
        return this.resolveDotNotation(eventRecord, dotNotation);
      }
      if (f.derivedFrom) {
        const sourceValue = eventRecord[f.derivedFrom];
        if (sourceValue instanceof Date) {
          return this.dateService.getDateKey(sourceValue);
        }
        return String(sourceValue || "");
      }
      return String(eventRecord[f.idProperty] || "");
    }).join(":");
  }
  /**
   * Resolve dot-notation reference via EntityResolver
   */
  resolveDotNotation(eventRecord, dotNotation) {
    if (!this.entityResolver) {
      console.warn(`FilterTemplate: EntityResolver required for dot-notation '${dotNotation.entityType}.${dotNotation.property}'`);
      return "";
    }
    const foreignId = eventRecord[dotNotation.foreignKey];
    if (!foreignId)
      return "";
    const entity = this.entityResolver.resolve(dotNotation.entityType, String(foreignId));
    if (!entity)
      return "";
    return String(entity[dotNotation.property] || "");
  }
  /**
   * Match event mod kolonne
   */
  matches(event, column) {
    return this.buildKeyFromEvent(event) === this.buildKeyFromColumn(column);
  }
};
var CalendarOrchestrator = class {
  constructor(allRenderers, eventRenderer, scheduleRenderer, headerDrawerRenderer, dateService, entityServices) {
    this.allRenderers = allRenderers;
    this.eventRenderer = eventRenderer;
    this.scheduleRenderer = scheduleRenderer;
    this.headerDrawerRenderer = headerDrawerRenderer;
    this.dateService = dateService;
    this.entityServices = entityServices;
  }
  async render(viewConfig, container) {
    const headerContainer = container.querySelector("swp-calendar-header");
    const columnContainer = container.querySelector("swp-day-columns");
    if (!headerContainer || !columnContainer) {
      throw new Error("Missing swp-calendar-header or swp-day-columns");
    }
    const filter = {};
    for (const grouping of viewConfig.groupings) {
      filter[grouping.type] = grouping.values;
    }
    const filterTemplate = new FilterTemplate(this.dateService);
    for (const grouping of viewConfig.groupings) {
      if (grouping.idProperty) {
        filterTemplate.addField(grouping.idProperty, grouping.derivedFrom);
      }
    }
    const { parentChildMap, childType } = await this.resolveBelongsTo(viewConfig.groupings, filter);
    const context = { headerContainer, columnContainer, filter, groupings: viewConfig.groupings, parentChildMap, childType };
    headerContainer.innerHTML = "";
    columnContainer.innerHTML = "";
    const levels = viewConfig.groupings.map((g) => g.type).join(" ");
    headerContainer.dataset.levels = levels;
    const activeRenderers = this.selectRenderers(viewConfig);
    const pipeline = buildPipeline(activeRenderers);
    await pipeline.run(context);
    await this.scheduleRenderer.render(container, filter);
    await this.eventRenderer.render(container, filter, filterTemplate);
    await this.headerDrawerRenderer.render(container, filter, filterTemplate);
  }
  selectRenderers(viewConfig) {
    const types = viewConfig.groupings.map((g) => g.type);
    return types.map((type) => this.allRenderers.find((r) => r.type === type)).filter((r) => r !== void 0);
  }
  /**
   * Resolve belongsTo relations to build parent-child map
   * e.g., belongsTo: 'team.resourceIds' → { team1: ['EMP001', 'EMP002'], team2: [...] }
   * Also returns the childType (the grouping type that has belongsTo)
   */
  async resolveBelongsTo(groupings, filter) {
    const childGrouping = groupings.find((g) => g.belongsTo);
    if (!childGrouping?.belongsTo)
      return {};
    const [entityType, property] = childGrouping.belongsTo.split(".");
    if (!entityType || !property)
      return {};
    const parentIds = filter[entityType] || [];
    if (parentIds.length === 0)
      return {};
    const service = this.entityServices.find((s) => s.entityType.toLowerCase() === entityType);
    if (!service)
      return {};
    const allEntities = await service.getAll();
    const entities = allEntities.filter((e) => parentIds.includes(e.id));
    const map = {};
    for (const entity of entities) {
      const entityRecord = entity;
      const children = entityRecord[property] || [];
      map[entityRecord.id] = children;
    }
    return { parentChildMap: map, childType: childGrouping.type };
  }
};
var EventBus = class {
  constructor() {
    this.eventLog = [];
    this.debug = false;
    this.listeners = /* @__PURE__ */ new Set();
    this.logConfig = {
      calendar: true,
      grid: true,
      event: true,
      scroll: true,
      navigation: true,
      view: true,
      default: true
    };
  }
  /**
   * Subscribe to an event via DOM addEventListener
   */
  on(eventType, handler, options) {
    document.addEventListener(eventType, handler, options);
    this.listeners.add({ eventType, handler, options });
    return () => this.off(eventType, handler);
  }
  /**
   * Subscribe to an event once
   */
  once(eventType, handler) {
    return this.on(eventType, handler, { once: true });
  }
  /**
   * Unsubscribe from an event
   */
  off(eventType, handler) {
    document.removeEventListener(eventType, handler);
    for (const listener of this.listeners) {
      if (listener.eventType === eventType && listener.handler === handler) {
        this.listeners.delete(listener);
        break;
      }
    }
  }
  /**
   * Emit an event via DOM CustomEvent
   */
  emit(eventType, detail = {}) {
    if (!eventType) {
      return false;
    }
    const event = new CustomEvent(eventType, {
      detail: detail ?? {},
      bubbles: true,
      cancelable: true
    });
    if (this.debug) {
      this.logEventWithGrouping(eventType, detail);
    }
    this.eventLog.push({
      type: eventType,
      detail: detail ?? {},
      timestamp: Date.now()
    });
    return !document.dispatchEvent(event);
  }
  /**
   * Log event with console grouping
   */
  logEventWithGrouping(eventType, _detail) {
    const category = this.extractCategory(eventType);
    if (!this.logConfig[category]) {
      return;
    }
    this.getCategoryStyle(category);
  }
  /**
   * Extract category from event type
   */
  extractCategory(eventType) {
    if (!eventType) {
      return "unknown";
    }
    if (eventType.includes(":")) {
      return eventType.split(":")[0];
    }
    const lowerType = eventType.toLowerCase();
    if (lowerType.includes("grid") || lowerType.includes("rendered"))
      return "grid";
    if (lowerType.includes("event") || lowerType.includes("sync"))
      return "event";
    if (lowerType.includes("scroll"))
      return "scroll";
    if (lowerType.includes("nav") || lowerType.includes("date"))
      return "navigation";
    if (lowerType.includes("view"))
      return "view";
    return "default";
  }
  /**
   * Get styling for different categories
   */
  getCategoryStyle(category) {
    const styles = {
      calendar: { emoji: "\u{1F4C5}", color: "#2196F3" },
      grid: { emoji: "\u{1F4CA}", color: "#4CAF50" },
      event: { emoji: "\u{1F4CC}", color: "#FF9800" },
      scroll: { emoji: "\u{1F4DC}", color: "#9C27B0" },
      navigation: { emoji: "\u{1F9ED}", color: "#F44336" },
      view: { emoji: "\u{1F441}", color: "#00BCD4" },
      default: { emoji: "\u{1F4E2}", color: "#607D8B" }
    };
    return styles[category] || styles.default;
  }
  /**
   * Configure logging for specific categories
   */
  setLogConfig(config) {
    this.logConfig = { ...this.logConfig, ...config };
  }
  /**
   * Get current log configuration
   */
  getLogConfig() {
    return { ...this.logConfig };
  }
  /**
   * Get event history
   */
  getEventLog(eventType) {
    if (eventType) {
      return this.eventLog.filter((e) => e.type === eventType);
    }
    return this.eventLog;
  }
  /**
   * Enable/disable debug mode
   */
  setDebug(enabled) {
    this.debug = enabled;
  }
};
import_dayjs.default.extend(import_utc.default);
import_dayjs.default.extend(import_timezone.default);
import_dayjs.default.extend(import_isoWeek.default);
var DateService = class {
  constructor(config, baseDate) {
    this.config = config;
    this.timezone = config.timezone;
    this.baseDate = baseDate ? (0, import_dayjs.default)(baseDate) : (0, import_dayjs.default)();
  }
  /**
   * Set a fixed base date (useful for demos with static mock data)
   */
  setBaseDate(date) {
    this.baseDate = (0, import_dayjs.default)(date);
  }
  /**
   * Get the current base date (either fixed or today)
   */
  getBaseDate() {
    return this.baseDate.toDate();
  }
  parseISO(isoString) {
    return (0, import_dayjs.default)(isoString).toDate();
  }
  getDayName(date, format = "short") {
    return new Intl.DateTimeFormat(this.config.locale, { weekday: format }).format(date);
  }
  /**
   * Get dates starting from a day offset
   * @param dayOffset - Day offset from base date
   * @param count - Number of consecutive days to return
   * @returns Array of date strings in YYYY-MM-DD format
   */
  getDatesFromOffset(dayOffset, count) {
    const startDate = this.baseDate.add(dayOffset, "day");
    return Array.from({ length: count }, (_, i) => startDate.add(i, "day").format("YYYY-MM-DD"));
  }
  /**
   * Get specific weekdays from the week containing the offset date
   * @param dayOffset - Day offset from base date
   * @param workDays - Array of ISO weekday numbers (1=Monday, 7=Sunday)
   * @returns Array of date strings in YYYY-MM-DD format
   */
  getWorkDaysFromOffset(dayOffset, workDays) {
    const targetDate = this.baseDate.add(dayOffset, "day");
    const monday = targetDate.startOf("week").add(1, "day");
    return workDays.map((isoDay) => {
      const daysFromMonday = isoDay === 7 ? 6 : isoDay - 1;
      return monday.add(daysFromMonday, "day").format("YYYY-MM-DD");
    });
  }
  // Legacy methods for backwards compatibility
  getWeekDates(weekOffset = 0, days = 7) {
    return this.getDatesFromOffset(weekOffset * 7, days);
  }
  getWorkWeekDates(weekOffset, workDays) {
    return this.getWorkDaysFromOffset(weekOffset * 7, workDays);
  }
  // ============================================
  // FORMATTING
  // ============================================
  formatTime(date, showSeconds = false) {
    const pattern = showSeconds ? "HH:mm:ss" : "HH:mm";
    return (0, import_dayjs.default)(date).format(pattern);
  }
  formatTimeRange(start, end) {
    return `${this.formatTime(start)} - ${this.formatTime(end)}`;
  }
  formatDate(date) {
    return (0, import_dayjs.default)(date).format("YYYY-MM-DD");
  }
  getDateKey(date) {
    return this.formatDate(date);
  }
  // ============================================
  // COLUMN KEY
  // ============================================
  /**
   * Build a uniform columnKey from grouping segments
   * Handles any combination of date, resource, team, etc.
   *
   * @example
   * buildColumnKey({ date: '2025-12-09' }) → "2025-12-09"
   * buildColumnKey({ date: '2025-12-09', resource: 'EMP001' }) → "2025-12-09:EMP001"
   */
  buildColumnKey(segments) {
    const date = segments.date;
    const others = Object.entries(segments).filter(([k]) => k !== "date").sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
    return date ? [date, ...others].join(":") : others.join(":");
  }
  /**
   * Parse a columnKey back into segments
   * Assumes format: "date:resource:..." or just "date"
   */
  parseColumnKey(columnKey) {
    const parts = columnKey.split(":");
    return {
      date: parts[0],
      resource: parts[1]
    };
  }
  /**
   * Extract dateKey from columnKey (first segment)
   */
  getDateFromColumnKey(columnKey) {
    return columnKey.split(":")[0];
  }
  // ============================================
  // TIME CALCULATIONS
  // ============================================
  timeToMinutes(timeString) {
    const parts = timeString.split(":").map(Number);
    const hours = parts[0] || 0;
    const minutes = parts[1] || 0;
    return hours * 60 + minutes;
  }
  minutesToTime(totalMinutes) {
    const hours = Math.floor(totalMinutes / 60);
    const minutes = totalMinutes % 60;
    return (0, import_dayjs.default)().hour(hours).minute(minutes).format("HH:mm");
  }
  getMinutesSinceMidnight(date) {
    const d = (0, import_dayjs.default)(date);
    return d.hour() * 60 + d.minute();
  }
  // ============================================
  // UTC CONVERSIONS
  // ============================================
  toUTC(localDate) {
    return import_dayjs.default.tz(localDate, this.timezone).utc().toISOString();
  }
  fromUTC(utcString) {
    return import_dayjs.default.utc(utcString).tz(this.timezone).toDate();
  }
  // ============================================
  // DATE CREATION
  // ============================================
  createDateAtTime(baseDate, timeString) {
    const totalMinutes = this.timeToMinutes(timeString);
    const hours = Math.floor(totalMinutes / 60);
    const minutes = totalMinutes % 60;
    return (0, import_dayjs.default)(baseDate).startOf("day").hour(hours).minute(minutes).toDate();
  }
  getISOWeekDay(date) {
    return (0, import_dayjs.default)(date).isoWeekday();
  }
};
var ScrollManager = class {
  init(container) {
    this.scrollableContent = container.querySelector("swp-scrollable-content");
    this.timeAxisContent = container.querySelector("swp-time-axis-content");
    this.calendarHeader = container.querySelector("swp-calendar-header");
    this.headerDrawer = container.querySelector("swp-header-drawer");
    this.headerViewport = container.querySelector("swp-header-viewport");
    this.headerSpacer = container.querySelector("swp-header-spacer");
    this.scrollableContent.addEventListener("scroll", () => this.onScroll());
    this.resizeObserver = new ResizeObserver(() => this.syncHeaderSpacerHeight());
    this.resizeObserver.observe(this.headerViewport);
    this.syncHeaderSpacerHeight();
  }
  syncHeaderSpacerHeight() {
    const computedHeight = getComputedStyle(this.headerViewport).height;
    this.headerSpacer.style.height = computedHeight;
  }
  onScroll() {
    const { scrollTop, scrollLeft } = this.scrollableContent;
    this.timeAxisContent.style.transform = `translateY(-${scrollTop}px)`;
    this.calendarHeader.style.transform = `translateX(-${scrollLeft}px)`;
    this.headerDrawer.style.transform = `translateX(-${scrollLeft}px)`;
  }
};
var HeaderDrawerManager = class {
  constructor() {
    this.expanded = false;
    this.currentRows = 0;
    this.rowHeight = 25;
    this.duration = 200;
  }
  init(container) {
    this.drawer = container.querySelector("swp-header-drawer");
    if (!this.drawer)
      console.error("HeaderDrawerManager: swp-header-drawer not found");
  }
  toggle() {
    this.expanded ? this.collapse() : this.expand();
  }
  /**
   * Expand drawer to single row (legacy support)
   */
  expand() {
    this.expandToRows(1);
  }
  /**
   * Expand drawer to fit specified number of rows
   */
  expandToRows(rowCount) {
    const targetHeight = rowCount * this.rowHeight;
    const currentHeight = this.expanded ? this.currentRows * this.rowHeight : 0;
    if (this.expanded && this.currentRows === rowCount)
      return;
    this.currentRows = rowCount;
    this.expanded = true;
    this.animate(currentHeight, targetHeight);
  }
  collapse() {
    if (!this.expanded)
      return;
    const currentHeight = this.currentRows * this.rowHeight;
    this.expanded = false;
    this.currentRows = 0;
    this.animate(currentHeight, 0);
  }
  animate(from, to) {
    const keyframes = [
      { height: `${from}px` },
      { height: `${to}px` }
    ];
    const options = {
      duration: this.duration,
      easing: "ease",
      fill: "forwards"
    };
    this.drawer.animate(keyframes, options);
  }
  isExpanded() {
    return this.expanded;
  }
  getRowCount() {
    return this.currentRows;
  }
};
var DateRenderer = class {
  constructor(dateService) {
    this.dateService = dateService;
    this.type = "date";
  }
  render(context) {
    const dates = context.filter["date"] || [];
    const resourceIds = context.filter["resource"] || [];
    const dateGrouping = context.groupings?.find((g) => g.type === "date");
    const hideHeader = dateGrouping?.hideHeader === true;
    const iterations = resourceIds.length || 1;
    let columnCount = 0;
    for (let r = 0; r < iterations; r++) {
      const resourceId = resourceIds[r];
      for (const dateStr of dates) {
        const date = this.dateService.parseISO(dateStr);
        const segments = { date: dateStr };
        if (resourceId)
          segments.resource = resourceId;
        const columnKey = this.dateService.buildColumnKey(segments);
        const header = document.createElement("swp-day-header");
        header.dataset.date = dateStr;
        header.dataset.columnKey = columnKey;
        if (resourceId) {
          header.dataset.resourceId = resourceId;
        }
        if (hideHeader) {
          header.dataset.hidden = "true";
        }
        header.innerHTML = `
          <swp-day-name>${this.dateService.getDayName(date, "short")}</swp-day-name>
          <swp-day-date>${date.getDate()}</swp-day-date>
        `;
        context.headerContainer.appendChild(header);
        const column = document.createElement("swp-day-column");
        column.dataset.date = dateStr;
        column.dataset.columnKey = columnKey;
        if (resourceId) {
          column.dataset.resourceId = resourceId;
        }
        column.innerHTML = "<swp-events-layer></swp-events-layer>";
        context.columnContainer.appendChild(column);
        columnCount++;
      }
    }
    const container = context.columnContainer.closest("swp-calendar-container");
    if (container) {
      container.style.setProperty("--grid-columns", String(columnCount));
    }
  }
};
var ResourceRenderer = class extends BaseGroupingRenderer {
  constructor(resourceService) {
    super();
    this.resourceService = resourceService;
    this.type = "resource";
    this.config = {
      elementTag: "swp-resource-header",
      idAttribute: "resourceId",
      colspanVar: "--resource-cols"
    };
  }
  getEntities(ids) {
    return this.resourceService.getByIds(ids);
  }
  getDisplayName(entity) {
    return entity.displayName;
  }
  /**
   * Override render to handle:
   * 1. Special ordering when parentChildMap exists (resources grouped by parent)
   * 2. Different colspan calculation (just dateCount, not childCount * dateCount)
   */
  async render(context) {
    const resourceIds = context.filter["resource"] || [];
    const dateCount = context.filter["date"]?.length || 1;
    let orderedResourceIds;
    if (context.parentChildMap) {
      orderedResourceIds = [];
      for (const childIds of Object.values(context.parentChildMap)) {
        for (const childId of childIds) {
          if (resourceIds.includes(childId)) {
            orderedResourceIds.push(childId);
          }
        }
      }
    } else {
      orderedResourceIds = resourceIds;
    }
    const resources = await this.getEntities(orderedResourceIds);
    const resourceMap = new Map(resources.map((r) => [r.id, r]));
    for (const resourceId of orderedResourceIds) {
      const resource = resourceMap.get(resourceId);
      if (!resource)
        continue;
      const header = this.createHeader(resource, context);
      header.style.gridColumn = `span ${dateCount}`;
      context.headerContainer.appendChild(header);
    }
  }
};
function calculateEventPosition(start, end, config) {
  const startMinutes = start.getHours() * 60 + start.getMinutes();
  const endMinutes = end.getHours() * 60 + end.getMinutes();
  const dayStartMinutes = config.dayStartHour * 60;
  const minuteHeight = config.hourHeight / 60;
  const top = (startMinutes - dayStartMinutes) * minuteHeight;
  const height = (endMinutes - startMinutes) * minuteHeight;
  return { top, height };
}
function minutesToPixels(minutes, config) {
  return minutes / 60 * config.hourHeight;
}
function pixelsToMinutes(pixels, config) {
  return pixels / config.hourHeight * 60;
}
function snapToGrid(pixels, config) {
  const snapPixels = minutesToPixels(config.snapInterval, config);
  return Math.round(pixels / snapPixels) * snapPixels;
}
function eventsOverlap(a, b) {
  return a.start < b.end && a.end > b.start;
}
function eventsWithinThreshold(a, b, thresholdMinutes) {
  const thresholdMs = thresholdMinutes * 60 * 1e3;
  const startToStartDiff = Math.abs(a.start.getTime() - b.start.getTime());
  if (startToStartDiff <= thresholdMs)
    return true;
  const bStartsBeforeAEnds = a.end.getTime() - b.start.getTime();
  if (bStartsBeforeAEnds > 0 && bStartsBeforeAEnds <= thresholdMs)
    return true;
  const aStartsBeforeBEnds = b.end.getTime() - a.start.getTime();
  if (aStartsBeforeBEnds > 0 && aStartsBeforeBEnds <= thresholdMs)
    return true;
  return false;
}
function findOverlapGroups(events) {
  if (events.length === 0)
    return [];
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  const used = /* @__PURE__ */ new Set();
  const groups = [];
  for (const event of sorted) {
    if (used.has(event.id))
      continue;
    const group = [event];
    used.add(event.id);
    let expanded = true;
    while (expanded) {
      expanded = false;
      for (const candidate of sorted) {
        if (used.has(candidate.id))
          continue;
        const connects = group.some((member) => eventsOverlap(member, candidate));
        if (connects) {
          group.push(candidate);
          used.add(candidate.id);
          expanded = true;
        }
      }
    }
    groups.push(group);
  }
  return groups;
}
function findGridCandidates(events, thresholdMinutes) {
  if (events.length === 0)
    return [];
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  const used = /* @__PURE__ */ new Set();
  const groups = [];
  for (const event of sorted) {
    if (used.has(event.id))
      continue;
    const group = [event];
    used.add(event.id);
    let expanded = true;
    while (expanded) {
      expanded = false;
      for (const candidate of sorted) {
        if (used.has(candidate.id))
          continue;
        const connects = group.some((member) => eventsWithinThreshold(member, candidate, thresholdMinutes));
        if (connects) {
          group.push(candidate);
          used.add(candidate.id);
          expanded = true;
        }
      }
    }
    groups.push(group);
  }
  return groups;
}
function calculateStackLevels(events) {
  const levels = /* @__PURE__ */ new Map();
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  for (const event of sorted) {
    let maxOverlappingLevel = -1;
    for (const [id, level] of levels) {
      const other = events.find((e) => e.id === id);
      if (other && eventsOverlap(event, other)) {
        maxOverlappingLevel = Math.max(maxOverlappingLevel, level);
      }
    }
    levels.set(event.id, maxOverlappingLevel + 1);
  }
  return levels;
}
function allocateColumns(events) {
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  const columns = [];
  for (const event of sorted) {
    let placed = false;
    for (const column of columns) {
      const canFit = !column.some((e) => eventsOverlap(event, e));
      if (canFit) {
        column.push(event);
        placed = true;
        break;
      }
    }
    if (!placed) {
      columns.push([event]);
    }
  }
  return columns;
}
function calculateColumnLayout(events, config) {
  const thresholdMinutes = config.gridStartThresholdMinutes ?? 10;
  const result = {
    grids: [],
    stacked: []
  };
  if (events.length === 0)
    return result;
  const overlapGroups = findOverlapGroups(events);
  for (const overlapGroup of overlapGroups) {
    if (overlapGroup.length === 1) {
      result.stacked.push({
        event: overlapGroup[0],
        stackLevel: 0
      });
      continue;
    }
    const gridSubgroups = findGridCandidates(overlapGroup, thresholdMinutes);
    const largestGridCandidate = gridSubgroups.reduce((max, g) => g.length > max.length ? g : max, gridSubgroups[0]);
    if (largestGridCandidate.length === overlapGroup.length) {
      const columns = allocateColumns(overlapGroup);
      const earliest = overlapGroup.reduce((min, e) => e.start < min.start ? e : min, overlapGroup[0]);
      const position = calculateEventPosition(earliest.start, earliest.end, config);
      result.grids.push({
        events: overlapGroup,
        columns,
        stackLevel: 0,
        position: { top: position.top }
      });
    } else {
      const levels = calculateStackLevels(overlapGroup);
      for (const event of overlapGroup) {
        result.stacked.push({
          event,
          stackLevel: levels.get(event.id) ?? 0
        });
      }
    }
  }
  return result;
}
var EventRenderer = class {
  constructor(eventService, dateService, gridConfig, eventBus) {
    this.eventService = eventService;
    this.dateService = dateService;
    this.gridConfig = gridConfig;
    this.eventBus = eventBus;
    this.container = null;
    this.setupListeners();
  }
  /**
   * Setup listeners for drag-drop and update events
   */
  setupListeners() {
    this.eventBus.on(CoreEvents.EVENT_DRAG_COLUMN_CHANGE, (e) => {
      const payload = e.detail;
      this.handleColumnChange(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_MOVE, (e) => {
      const payload = e.detail;
      this.updateDragTimestamp(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_UPDATED, (e) => {
      const payload = e.detail;
      this.handleEventUpdated(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_END, (e) => {
      const payload = e.detail;
      this.handleDragEnd(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_LEAVE_HEADER, (e) => {
      const payload = e.detail;
      this.handleDragLeaveHeader(payload);
    });
  }
  /**
   * Handle EVENT_DRAG_END - remove element if dropped in header
   */
  handleDragEnd(payload) {
    if (payload.target === "header") {
      const element = this.container?.querySelector(`swp-content-viewport swp-event[data-event-id="${payload.swpEvent.eventId}"]`);
      element?.remove();
    }
  }
  /**
   * Handle header item leaving header - create swp-event in grid
   */
  handleDragLeaveHeader(payload) {
    if (payload.source !== "header")
      return;
    if (!payload.targetColumn || !payload.start || !payload.end)
      return;
    if (payload.element) {
      payload.element.classList.add("drag-ghost");
      payload.element.style.opacity = "0.3";
      payload.element.style.pointerEvents = "none";
    }
    const event = {
      id: payload.eventId,
      title: payload.title || "",
      description: "",
      start: payload.start,
      end: payload.end,
      type: "customer",
      allDay: false,
      syncStatus: "pending"
    };
    const element = this.createEventElement(event);
    let eventsLayer = payload.targetColumn.querySelector("swp-events-layer");
    if (!eventsLayer) {
      eventsLayer = document.createElement("swp-events-layer");
      payload.targetColumn.appendChild(eventsLayer);
    }
    eventsLayer.appendChild(element);
    element.classList.add("dragging");
  }
  /**
   * Handle EVENT_UPDATED - re-render affected columns
   */
  async handleEventUpdated(payload) {
    if (payload.sourceColumnKey !== payload.targetColumnKey) {
      await this.rerenderColumn(payload.sourceColumnKey);
    }
    await this.rerenderColumn(payload.targetColumnKey);
  }
  /**
   * Re-render a single column with fresh data from IndexedDB
   */
  async rerenderColumn(columnKey) {
    const column = this.findColumn(columnKey);
    if (!column)
      return;
    const date = column.dataset.date;
    const resourceId = column.dataset.resourceId;
    if (!date)
      return;
    const startDate = new Date(date);
    const endDate = new Date(date);
    endDate.setHours(23, 59, 59, 999);
    const events = resourceId ? await this.eventService.getByResourceAndDateRange(resourceId, startDate, endDate) : await this.eventService.getByDateRange(startDate, endDate);
    const timedEvents = events.filter((event) => !event.allDay && this.dateService.getDateKey(event.start) === date);
    let eventsLayer = column.querySelector("swp-events-layer");
    if (!eventsLayer) {
      eventsLayer = document.createElement("swp-events-layer");
      column.appendChild(eventsLayer);
    }
    eventsLayer.innerHTML = "";
    const layout = calculateColumnLayout(timedEvents, this.gridConfig);
    layout.grids.forEach((grid) => {
      const groupEl = this.renderGridGroup(grid);
      eventsLayer.appendChild(groupEl);
    });
    layout.stacked.forEach((item) => {
      const eventEl = this.renderStackedEvent(item.event, item.stackLevel);
      eventsLayer.appendChild(eventEl);
    });
  }
  /**
   * Find a column element by columnKey
   */
  findColumn(columnKey) {
    if (!this.container)
      return null;
    return this.container.querySelector(`swp-day-column[data-column-key="${columnKey}"]`);
  }
  /**
   * Handle event moving to a new column during drag
   */
  handleColumnChange(payload) {
    const eventsLayer = payload.newColumn.querySelector("swp-events-layer");
    if (!eventsLayer)
      return;
    eventsLayer.appendChild(payload.element);
    payload.element.style.top = `${payload.currentY}px`;
  }
  /**
   * Update timestamp display during drag (snapped to grid)
   */
  updateDragTimestamp(payload) {
    const timeEl = payload.element.querySelector("swp-event-time");
    if (!timeEl)
      return;
    const snappedY = snapToGrid(payload.currentY, this.gridConfig);
    const minutesFromGridStart = pixelsToMinutes(snappedY, this.gridConfig);
    const startMinutes = this.gridConfig.dayStartHour * 60 + minutesFromGridStart;
    const height = parseFloat(payload.element.style.height) || this.gridConfig.hourHeight;
    const durationMinutes = pixelsToMinutes(height, this.gridConfig);
    const start = this.minutesToDate(startMinutes);
    const end = this.minutesToDate(startMinutes + durationMinutes);
    timeEl.textContent = this.dateService.formatTimeRange(start, end);
  }
  /**
   * Convert minutes since midnight to a Date object (today)
   */
  minutesToDate(minutes) {
    const date = /* @__PURE__ */ new Date();
    date.setHours(Math.floor(minutes / 60) % 24, minutes % 60, 0, 0);
    return date;
  }
  /**
   * Render events for visible dates into day columns
   * @param container - Calendar container element
   * @param filter - Filter with 'date' and optionally 'resource' arrays
   * @param filterTemplate - Template for matching events to columns
   */
  async render(container, filter, filterTemplate) {
    this.container = container;
    const visibleDates = filter["date"] || [];
    if (visibleDates.length === 0)
      return;
    const startDate = new Date(visibleDates[0]);
    const endDate = new Date(visibleDates[visibleDates.length - 1]);
    endDate.setHours(23, 59, 59, 999);
    const events = await this.eventService.getByDateRange(startDate, endDate);
    const dayColumns = container.querySelector("swp-day-columns");
    if (!dayColumns)
      return;
    const columns = dayColumns.querySelectorAll("swp-day-column");
    columns.forEach((column) => {
      const columnEl = column;
      const columnEvents = events.filter((event) => filterTemplate.matches(event, columnEl));
      let eventsLayer = column.querySelector("swp-events-layer");
      if (!eventsLayer) {
        eventsLayer = document.createElement("swp-events-layer");
        column.appendChild(eventsLayer);
      }
      eventsLayer.innerHTML = "";
      const timedEvents = columnEvents.filter((event) => !event.allDay);
      const layout = calculateColumnLayout(timedEvents, this.gridConfig);
      layout.grids.forEach((grid) => {
        const groupEl = this.renderGridGroup(grid);
        eventsLayer.appendChild(groupEl);
      });
      layout.stacked.forEach((item) => {
        const eventEl = this.renderStackedEvent(item.event, item.stackLevel);
        eventsLayer.appendChild(eventEl);
      });
    });
  }
  /**
   * Create a single event element
   *
   * CLEAN approach:
   * - Only data-id for lookup
   * - Visible content in innerHTML only
   */
  createEventElement(event) {
    const element = document.createElement("swp-event");
    element.dataset.eventId = event.id;
    if (event.resourceId) {
      element.dataset.resourceId = event.resourceId;
    }
    const position = calculateEventPosition(event.start, event.end, this.gridConfig);
    element.style.top = `${position.top}px`;
    element.style.height = `${position.height}px`;
    const colorClass = this.getColorClass(event);
    if (colorClass) {
      element.classList.add(colorClass);
    }
    element.innerHTML = `
      <swp-event-time>${this.dateService.formatTimeRange(event.start, event.end)}</swp-event-time>
      <swp-event-title>${this.escapeHtml(event.title)}</swp-event-title>
      ${event.description ? `<swp-event-description>${this.escapeHtml(event.description)}</swp-event-description>` : ""}
    `;
    return element;
  }
  /**
   * Get color class based on metadata.color or event type
   */
  getColorClass(event) {
    if (event.metadata?.color) {
      return `is-${event.metadata.color}`;
    }
    const typeColors = {
      "customer": "is-blue",
      "vacation": "is-green",
      "break": "is-amber",
      "meeting": "is-purple",
      "blocked": "is-red"
    };
    return typeColors[event.type] || "is-blue";
  }
  /**
   * Escape HTML to prevent XSS
   */
  escapeHtml(text) {
    const div = document.createElement("div");
    div.textContent = text;
    return div.innerHTML;
  }
  /**
   * Render a GRID group with side-by-side columns
   * Used when multiple events start at the same time
   */
  renderGridGroup(layout) {
    const group = document.createElement("swp-event-group");
    group.classList.add(`cols-${layout.columns.length}`);
    group.style.top = `${layout.position.top}px`;
    if (layout.stackLevel > 0) {
      group.style.marginLeft = `${layout.stackLevel * 15}px`;
      group.style.zIndex = `${100 + layout.stackLevel}`;
    }
    let maxBottom = 0;
    for (const event of layout.events) {
      const pos = calculateEventPosition(event.start, event.end, this.gridConfig);
      const eventBottom = pos.top + pos.height;
      if (eventBottom > maxBottom)
        maxBottom = eventBottom;
    }
    const groupHeight = maxBottom - layout.position.top;
    group.style.height = `${groupHeight}px`;
    layout.columns.forEach((columnEvents) => {
      const wrapper = document.createElement("div");
      wrapper.style.position = "relative";
      columnEvents.forEach((event) => {
        const eventEl = this.createEventElement(event);
        const pos = calculateEventPosition(event.start, event.end, this.gridConfig);
        eventEl.style.top = `${pos.top - layout.position.top}px`;
        eventEl.style.position = "absolute";
        eventEl.style.left = "0";
        eventEl.style.right = "0";
        wrapper.appendChild(eventEl);
      });
      group.appendChild(wrapper);
    });
    return group;
  }
  /**
   * Render a STACKED event with margin-left offset
   * Used for overlapping events that don't start at the same time
   */
  renderStackedEvent(event, stackLevel) {
    const element = this.createEventElement(event);
    element.dataset.stackLink = JSON.stringify({ stackLevel });
    if (stackLevel > 0) {
      element.style.marginLeft = `${stackLevel * 15}px`;
      element.style.zIndex = `${100 + stackLevel}`;
    }
    return element;
  }
};
var TimeAxisRenderer = class {
  render(container, startHour = 6, endHour = 20) {
    container.innerHTML = "";
    for (let hour = startHour; hour <= endHour; hour++) {
      const marker = document.createElement("swp-hour-marker");
      marker.textContent = `${hour.toString().padStart(2, "0")}:00`;
      container.appendChild(marker);
    }
  }
};
var HeaderDrawerRenderer = class {
  constructor(eventBus, gridConfig, headerDrawerManager, eventService, dateService) {
    this.eventBus = eventBus;
    this.gridConfig = gridConfig;
    this.headerDrawerManager = headerDrawerManager;
    this.eventService = eventService;
    this.dateService = dateService;
    this.currentItem = null;
    this.container = null;
    this.sourceElement = null;
    this.wasExpandedBeforeDrag = false;
    this.filterTemplate = null;
    this.setupListeners();
  }
  /**
   * Render allDay events into the header drawer with row stacking
   * @param filterTemplate - Template for matching events to columns
   */
  async render(container, filter, filterTemplate) {
    this.filterTemplate = filterTemplate;
    const drawer = container.querySelector("swp-header-drawer");
    if (!drawer)
      return;
    const visibleDates = filter["date"] || [];
    if (visibleDates.length === 0)
      return;
    const visibleColumnKeys = this.getVisibleColumnKeysFromDOM();
    if (visibleColumnKeys.length === 0)
      return;
    const startDate = new Date(visibleDates[0]);
    const endDate = new Date(visibleDates[visibleDates.length - 1]);
    endDate.setHours(23, 59, 59, 999);
    const events = await this.eventService.getByDateRange(startDate, endDate);
    const allDayEvents = events.filter((event) => event.allDay !== false);
    drawer.innerHTML = "";
    if (allDayEvents.length === 0)
      return;
    const layouts = this.calculateLayout(allDayEvents, visibleColumnKeys);
    const rowCount = Math.max(1, ...layouts.map((l) => l.row));
    layouts.forEach((layout) => {
      const item = this.createHeaderItem(layout);
      drawer.appendChild(item);
    });
    this.headerDrawerManager.expandToRows(rowCount);
  }
  /**
   * Create a header item element from layout
   */
  createHeaderItem(layout) {
    const { event, columnKey, row, colStart, colEnd } = layout;
    const item = document.createElement("swp-header-item");
    item.dataset.eventId = event.id;
    item.dataset.itemType = "event";
    item.dataset.start = event.start.toISOString();
    item.dataset.end = event.end.toISOString();
    item.dataset.columnKey = columnKey;
    item.textContent = event.title;
    const colorClass = this.getColorClass(event);
    if (colorClass)
      item.classList.add(colorClass);
    item.style.gridArea = `${row} / ${colStart} / ${row + 1} / ${colEnd}`;
    return item;
  }
  /**
   * Calculate layout for all events with row stacking
   * Uses track-based algorithm to find available rows for overlapping events
   */
  calculateLayout(events, visibleColumnKeys) {
    const tracks = [new Array(visibleColumnKeys.length).fill(false)];
    const layouts = [];
    for (const event of events) {
      const columnKey = this.buildColumnKeyFromEvent(event);
      const startCol = visibleColumnKeys.indexOf(columnKey);
      const endColumnKey = this.buildColumnKeyFromEvent(event, event.end);
      const endCol = visibleColumnKeys.indexOf(endColumnKey);
      if (startCol === -1 && endCol === -1)
        continue;
      const colStart = Math.max(0, startCol);
      const colEnd = (endCol !== -1 ? endCol : visibleColumnKeys.length - 1) + 1;
      const row = this.findAvailableRow(tracks, colStart, colEnd);
      for (let c = colStart; c < colEnd; c++) {
        tracks[row][c] = true;
      }
      layouts.push({ event, columnKey, row: row + 1, colStart: colStart + 1, colEnd: colEnd + 1 });
    }
    return layouts;
  }
  /**
   * Build columnKey from event using FilterTemplate
   * Uses the same template that columns use for matching
   */
  buildColumnKeyFromEvent(event, date) {
    if (!this.filterTemplate) {
      const dateStr = this.dateService.getDateKey(date || event.start);
      return dateStr;
    }
    if (date && date.getTime() !== event.start.getTime()) {
      const tempEvent = { ...event, start: date };
      return this.filterTemplate.buildKeyFromEvent(tempEvent);
    }
    return this.filterTemplate.buildKeyFromEvent(event);
  }
  /**
   * Find available row for event spanning columns [colStart, colEnd)
   */
  findAvailableRow(tracks, colStart, colEnd) {
    for (let row = 0; row < tracks.length; row++) {
      let available = true;
      for (let c = colStart; c < colEnd; c++) {
        if (tracks[row][c]) {
          available = false;
          break;
        }
      }
      if (available)
        return row;
    }
    tracks.push(new Array(tracks[0].length).fill(false));
    return tracks.length - 1;
  }
  /**
   * Get color class based on event metadata or type
   */
  getColorClass(event) {
    if (event.metadata?.color) {
      return `is-${event.metadata.color}`;
    }
    const typeColors = {
      "customer": "is-blue",
      "vacation": "is-green",
      "break": "is-amber",
      "meeting": "is-purple",
      "blocked": "is-red"
    };
    return typeColors[event.type] || "is-blue";
  }
  /**
   * Setup event listeners for drag events
   */
  setupListeners() {
    this.eventBus.on(CoreEvents.EVENT_DRAG_ENTER_HEADER, (e) => {
      const payload = e.detail;
      this.handleDragEnter(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_MOVE_HEADER, (e) => {
      const payload = e.detail;
      this.handleDragMove(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_LEAVE_HEADER, (e) => {
      const payload = e.detail;
      this.handleDragLeave(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_END, (e) => {
      const payload = e.detail;
      this.handleDragEnd(payload);
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_CANCEL, () => {
      this.cleanup();
    });
  }
  /**
   * Handle drag entering header zone - create preview item
   */
  handleDragEnter(payload) {
    this.container = document.querySelector("swp-header-drawer");
    if (!this.container)
      return;
    this.wasExpandedBeforeDrag = this.headerDrawerManager.isExpanded();
    if (!this.wasExpandedBeforeDrag) {
      this.headerDrawerManager.expandToRows(1);
    }
    this.sourceElement = payload.element;
    const item = document.createElement("swp-header-item");
    item.dataset.eventId = payload.eventId;
    item.dataset.itemType = payload.itemType;
    item.dataset.duration = String(payload.duration);
    item.dataset.columnKey = payload.sourceColumnKey;
    item.textContent = payload.title;
    if (payload.colorClass) {
      item.classList.add(payload.colorClass);
    }
    item.classList.add("dragging");
    const col = payload.sourceColumnIndex + 1;
    const endCol = col + payload.duration;
    item.style.gridArea = `1 / ${col} / 2 / ${endCol}`;
    this.container.appendChild(item);
    this.currentItem = item;
    payload.element.style.visibility = "hidden";
  }
  /**
   * Handle drag moving within header - update column position
   */
  handleDragMove(payload) {
    if (!this.currentItem)
      return;
    const col = payload.columnIndex + 1;
    const duration = parseInt(this.currentItem.dataset.duration || "1", 10);
    const endCol = col + duration;
    this.currentItem.style.gridArea = `1 / ${col} / 2 / ${endCol}`;
    this.currentItem.dataset.columnKey = payload.columnKey;
  }
  /**
   * Handle drag leaving header - cleanup for grid→header drag only
   */
  handleDragLeave(payload) {
    if (payload.source === "grid") {
      this.cleanup();
    }
  }
  /**
   * Handle drag end - finalize based on drop target
   */
  handleDragEnd(payload) {
    if (payload.target === "header") {
      if (this.currentItem) {
        this.currentItem.classList.remove("dragging");
        this.recalculateDrawerLayout();
        this.currentItem = null;
        this.sourceElement = null;
      }
    } else {
      const ghost = document.querySelector(`swp-header-item.drag-ghost[data-event-id="${payload.swpEvent.eventId}"]`);
      ghost?.remove();
      this.recalculateDrawerLayout();
    }
  }
  /**
   * Recalculate layout for all items currently in the drawer
   * Called after drop to reposition items and adjust height
   */
  recalculateDrawerLayout() {
    const drawer = document.querySelector("swp-header-drawer");
    if (!drawer)
      return;
    const items = Array.from(drawer.querySelectorAll("swp-header-item"));
    if (items.length === 0)
      return;
    const visibleColumnKeys = this.getVisibleColumnKeysFromDOM();
    if (visibleColumnKeys.length === 0)
      return;
    const itemData = items.map((item) => ({
      element: item,
      columnKey: item.dataset.columnKey || "",
      duration: parseInt(item.dataset.duration || "1", 10)
    }));
    const tracks = [new Array(visibleColumnKeys.length).fill(false)];
    for (const item of itemData) {
      const startCol = visibleColumnKeys.indexOf(item.columnKey);
      if (startCol === -1)
        continue;
      const colStart = startCol;
      const colEnd = Math.min(startCol + item.duration, visibleColumnKeys.length);
      const row = this.findAvailableRow(tracks, colStart, colEnd);
      for (let c = colStart; c < colEnd; c++) {
        tracks[row][c] = true;
      }
      item.element.style.gridArea = `${row + 1} / ${colStart + 1} / ${row + 2} / ${colEnd + 1}`;
    }
    const rowCount = tracks.length;
    this.headerDrawerManager.expandToRows(rowCount);
  }
  /**
   * Get visible column keys from DOM (preserves order for multi-resource views)
   * Uses filterTemplate.buildKeyFromColumn() for consistent key format with events
   */
  getVisibleColumnKeysFromDOM() {
    if (!this.filterTemplate)
      return [];
    const columns = document.querySelectorAll("swp-day-column");
    const columnKeys = [];
    columns.forEach((col) => {
      const columnKey = this.filterTemplate.buildKeyFromColumn(col);
      if (columnKey)
        columnKeys.push(columnKey);
    });
    return columnKeys;
  }
  /**
   * Cleanup preview item and restore source visibility
   */
  cleanup() {
    this.currentItem?.remove();
    this.currentItem = null;
    if (this.sourceElement) {
      this.sourceElement.style.visibility = "";
      this.sourceElement = null;
    }
    if (!this.wasExpandedBeforeDrag) {
      this.headerDrawerManager.collapse();
    }
  }
};
var ScheduleRenderer = class {
  constructor(scheduleService, dateService, gridConfig) {
    this.scheduleService = scheduleService;
    this.dateService = dateService;
    this.gridConfig = gridConfig;
  }
  /**
   * Render unavailable zones for visible columns
   * @param container - Calendar container element
   * @param filter - Filter with 'date' and 'resource' arrays
   */
  async render(container, filter) {
    const dates = filter["date"] || [];
    const resourceIds = filter["resource"] || [];
    if (dates.length === 0)
      return;
    const dayColumns = container.querySelector("swp-day-columns");
    if (!dayColumns)
      return;
    const columns = dayColumns.querySelectorAll("swp-day-column");
    for (const column of columns) {
      const date = column.dataset.date;
      const resourceId = column.dataset.resourceId;
      if (!date || !resourceId)
        continue;
      let unavailableLayer = column.querySelector("swp-unavailable-layer");
      if (!unavailableLayer) {
        unavailableLayer = document.createElement("swp-unavailable-layer");
        column.insertBefore(unavailableLayer, column.firstChild);
      }
      unavailableLayer.innerHTML = "";
      const schedule = await this.scheduleService.getScheduleForDate(resourceId, date);
      this.renderUnavailableZones(unavailableLayer, schedule);
    }
  }
  /**
   * Render unavailable time zones based on schedule
   */
  renderUnavailableZones(layer, schedule) {
    const dayStartMinutes = this.gridConfig.dayStartHour * 60;
    const dayEndMinutes = this.gridConfig.dayEndHour * 60;
    const minuteHeight = this.gridConfig.hourHeight / 60;
    if (schedule === null) {
      const zone = this.createUnavailableZone(0, (dayEndMinutes - dayStartMinutes) * minuteHeight);
      layer.appendChild(zone);
      return;
    }
    const workStartMinutes = this.dateService.timeToMinutes(schedule.start);
    const workEndMinutes = this.dateService.timeToMinutes(schedule.end);
    if (workStartMinutes > dayStartMinutes) {
      const top = 0;
      const height = (workStartMinutes - dayStartMinutes) * minuteHeight;
      const zone = this.createUnavailableZone(top, height);
      layer.appendChild(zone);
    }
    if (workEndMinutes < dayEndMinutes) {
      const top = (workEndMinutes - dayStartMinutes) * minuteHeight;
      const height = (dayEndMinutes - workEndMinutes) * minuteHeight;
      const zone = this.createUnavailableZone(top, height);
      layer.appendChild(zone);
    }
  }
  /**
   * Create an unavailable zone element
   */
  createUnavailableZone(top, height) {
    const zone = document.createElement("swp-unavailable-zone");
    zone.style.top = `${top}px`;
    zone.style.height = `${height}px`;
    return zone;
  }
};
var defaultDBConfig = {
  dbName: "CalendarDB",
  dbVersion: 4
};
var IndexedDBContext = class {
  constructor(stores, config) {
    this.db = null;
    this.initialized = false;
    this.stores = stores;
    this.config = config;
  }
  get dbName() {
    return this.config.dbName;
  }
  /**
   * Initialize and open the database
   */
  async initialize() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.config.dbName, this.config.dbVersion);
      request.onerror = () => {
        reject(new Error(`Failed to open IndexedDB: ${request.error}`));
      };
      request.onsuccess = () => {
        this.db = request.result;
        this.initialized = true;
        resolve();
      };
      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        this.stores.forEach((store) => {
          if (!db.objectStoreNames.contains(store.storeName)) {
            store.create(db);
          }
        });
      };
    });
  }
  /**
   * Check if database is initialized
   */
  isInitialized() {
    return this.initialized;
  }
  /**
   * Get IDBDatabase instance
   */
  getDatabase() {
    if (!this.db) {
      throw new Error("IndexedDB not initialized. Call initialize() first.");
    }
    return this.db;
  }
  /**
   * Close database connection
   */
  close() {
    if (this.db) {
      this.db.close();
      this.db = null;
      this.initialized = false;
    }
  }
  /**
   * Delete entire database (for testing/reset)
   */
  static async deleteDatabase(dbName = defaultDBConfig.dbName) {
    return new Promise((resolve, reject) => {
      const request = indexedDB.deleteDatabase(dbName);
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error(`Failed to delete database: ${request.error}`));
    });
  }
};
var EventStore = class _EventStore {
  constructor() {
    this.storeName = _EventStore.STORE_NAME;
  }
  /**
   * Create the events ObjectStore with indexes
   */
  create(db) {
    const store = db.createObjectStore(_EventStore.STORE_NAME, { keyPath: "id" });
    store.createIndex("start", "start", { unique: false });
    store.createIndex("end", "end", { unique: false });
    store.createIndex("syncStatus", "syncStatus", { unique: false });
    store.createIndex("resourceId", "resourceId", { unique: false });
    store.createIndex("customerId", "customerId", { unique: false });
    store.createIndex("bookingId", "bookingId", { unique: false });
    store.createIndex("startEnd", ["start", "end"], { unique: false });
  }
};
EventStore.STORE_NAME = "events";
var EventSerialization = class {
  /**
   * Serialize event for IndexedDB storage
   */
  static serialize(event) {
    return {
      ...event,
      start: event.start instanceof Date ? event.start.toISOString() : event.start,
      end: event.end instanceof Date ? event.end.toISOString() : event.end
    };
  }
  /**
   * Deserialize event from IndexedDB storage
   */
  static deserialize(data) {
    return {
      ...data,
      start: typeof data.start === "string" ? new Date(data.start) : data.start,
      end: typeof data.end === "string" ? new Date(data.end) : data.end
    };
  }
};
var EventService = class extends BaseEntityService {
  constructor(context, eventBus) {
    super(context, eventBus);
    this.storeName = EventStore.STORE_NAME;
    this.entityType = "Event";
  }
  serialize(event) {
    return EventSerialization.serialize(event);
  }
  deserialize(data) {
    return EventSerialization.deserialize(data);
  }
  /**
   * Get events within a date range
   */
  async getByDateRange(start, end) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readonly");
      const store = transaction.objectStore(this.storeName);
      const index = store.index("start");
      const range = IDBKeyRange.lowerBound(start.toISOString());
      const request = index.getAll(range);
      request.onsuccess = () => {
        const data = request.result;
        const events = data.map((item) => this.deserialize(item)).filter((event) => event.start <= end);
        resolve(events);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get events by date range: ${request.error}`));
      };
    });
  }
  /**
   * Get events for a specific resource
   */
  async getByResource(resourceId) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readonly");
      const store = transaction.objectStore(this.storeName);
      const index = store.index("resourceId");
      const request = index.getAll(resourceId);
      request.onsuccess = () => {
        const data = request.result;
        const events = data.map((item) => this.deserialize(item));
        resolve(events);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get events for resource ${resourceId}: ${request.error}`));
      };
    });
  }
  /**
   * Get events for a resource within a date range
   */
  async getByResourceAndDateRange(resourceId, start, end) {
    const resourceEvents = await this.getByResource(resourceId);
    return resourceEvents.filter((event) => event.start >= start && event.start <= end);
  }
};
var ResourceStore = class _ResourceStore {
  constructor() {
    this.storeName = _ResourceStore.STORE_NAME;
  }
  create(db) {
    const store = db.createObjectStore(_ResourceStore.STORE_NAME, { keyPath: "id" });
    store.createIndex("type", "type", { unique: false });
    store.createIndex("syncStatus", "syncStatus", { unique: false });
    store.createIndex("isActive", "isActive", { unique: false });
  }
};
ResourceStore.STORE_NAME = "resources";
var ResourceService = class extends BaseEntityService {
  constructor(context, eventBus) {
    super(context, eventBus);
    this.storeName = ResourceStore.STORE_NAME;
    this.entityType = "Resource";
  }
  /**
   * Get all active resources
   */
  async getActive() {
    const all = await this.getAll();
    return all.filter((r) => r.isActive !== false);
  }
  /**
   * Get resources by IDs
   */
  async getByIds(ids) {
    if (ids.length === 0)
      return [];
    const results = await Promise.all(ids.map((id) => this.get(id)));
    return results.filter((r) => r !== null);
  }
  /**
   * Get resources by type
   */
  async getByType(type) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], "readonly");
      const store = transaction.objectStore(this.storeName);
      const index = store.index("type");
      const request = index.getAll(type);
      request.onsuccess = () => {
        const data = request.result;
        resolve(data);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get resources by type ${type}: ${request.error}`));
      };
    });
  }
};
var SettingsIds = {
  WORKWEEK: "workweek",
  GRID: "grid",
  TIME_FORMAT: "timeFormat",
  VIEWS: "views"
};
var SettingsStore = class _SettingsStore {
  constructor() {
    this.storeName = _SettingsStore.STORE_NAME;
  }
  create(db) {
    db.createObjectStore(_SettingsStore.STORE_NAME, { keyPath: "id" });
  }
};
SettingsStore.STORE_NAME = "settings";
var SettingsService = class extends BaseEntityService {
  constructor(context, eventBus) {
    super(context, eventBus);
    this.storeName = SettingsStore.STORE_NAME;
    this.entityType = "Settings";
  }
  /**
   * Get workweek settings
   */
  async getWorkweekSettings() {
    return this.get(SettingsIds.WORKWEEK);
  }
  /**
   * Get grid settings
   */
  async getGridSettings() {
    return this.get(SettingsIds.GRID);
  }
  /**
   * Get time format settings
   */
  async getTimeFormatSettings() {
    return this.get(SettingsIds.TIME_FORMAT);
  }
  /**
   * Get view settings
   */
  async getViewSettings() {
    return this.get(SettingsIds.VIEWS);
  }
  /**
   * Get workweek preset by ID
   */
  async getWorkweekPreset(presetId) {
    const settings = await this.getWorkweekSettings();
    if (!settings)
      return null;
    return settings.presets[presetId] || null;
  }
  /**
   * Get the default workweek preset
   */
  async getDefaultWorkweekPreset() {
    const settings = await this.getWorkweekSettings();
    if (!settings)
      return null;
    return settings.presets[settings.defaultPreset] || null;
  }
  /**
   * Get all available workweek presets
   */
  async getWorkweekPresets() {
    const settings = await this.getWorkweekSettings();
    if (!settings)
      return [];
    return Object.values(settings.presets);
  }
};
var ViewConfigStore = class _ViewConfigStore {
  constructor() {
    this.storeName = _ViewConfigStore.STORE_NAME;
  }
  create(db) {
    db.createObjectStore(_ViewConfigStore.STORE_NAME, { keyPath: "id" });
  }
};
ViewConfigStore.STORE_NAME = "viewconfigs";
var ViewConfigService = class extends BaseEntityService {
  constructor(context, eventBus) {
    super(context, eventBus);
    this.storeName = ViewConfigStore.STORE_NAME;
    this.entityType = "ViewConfig";
  }
  async getById(id) {
    return this.get(id);
  }
};
var SwpEvent = class _SwpEvent {
  constructor(element, columnKey, start, end) {
    this.element = element;
    this.columnKey = columnKey;
    this._start = start;
    this._end = end;
  }
  /** Event ID from element.dataset.eventId */
  get eventId() {
    return this.element.dataset.eventId || "";
  }
  get start() {
    return this._start;
  }
  get end() {
    return this._end;
  }
  /** Duration in minutes */
  get durationMinutes() {
    return (this._end.getTime() - this._start.getTime()) / (1e3 * 60);
  }
  /** Duration in milliseconds */
  get durationMs() {
    return this._end.getTime() - this._start.getTime();
  }
  /**
   * Factory: Create SwpEvent from element + columnKey
   * Reads top/height from element.style to calculate start/end
   * @param columnKey - Opaque column identifier (do NOT parse - use only for matching)
   * @param date - Date string (YYYY-MM-DD) for time calculations
   */
  static fromElement(element, columnKey, date, gridConfig) {
    const topPixels = parseFloat(element.style.top) || 0;
    const heightPixels = parseFloat(element.style.height) || 0;
    const startMinutesFromGrid = topPixels / gridConfig.hourHeight * 60;
    const totalMinutes = gridConfig.dayStartHour * 60 + startMinutesFromGrid;
    const start = new Date(date);
    start.setHours(Math.floor(totalMinutes / 60), totalMinutes % 60, 0, 0);
    const durationMinutes = heightPixels / gridConfig.hourHeight * 60;
    const end = new Date(start.getTime() + durationMinutes * 60 * 1e3);
    return new _SwpEvent(element, columnKey, start, end);
  }
};
var DragDropManager = class {
  constructor(eventBus, gridConfig) {
    this.eventBus = eventBus;
    this.gridConfig = gridConfig;
    this.dragState = null;
    this.mouseDownPosition = null;
    this.pendingElement = null;
    this.pendingMouseOffset = null;
    this.container = null;
    this.inHeader = false;
    this.DRAG_THRESHOLD = 5;
    this.INTERPOLATION_FACTOR = 0.3;
    this.handlePointerDown = (e) => {
      const target = e.target;
      if (target.closest("swp-resize-handle"))
        return;
      const eventElement = target.closest("swp-event");
      const headerItem = target.closest("swp-header-item");
      const draggable = eventElement || headerItem;
      if (!draggable)
        return;
      this.mouseDownPosition = { x: e.clientX, y: e.clientY };
      this.pendingElement = draggable;
      const rect = draggable.getBoundingClientRect();
      this.pendingMouseOffset = {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top
      };
      draggable.setPointerCapture(e.pointerId);
    };
    this.handlePointerMove = (e) => {
      if (!this.mouseDownPosition || !this.pendingElement) {
        if (this.dragState) {
          this.updateDragTarget(e);
        }
        return;
      }
      const deltaX = Math.abs(e.clientX - this.mouseDownPosition.x);
      const deltaY = Math.abs(e.clientY - this.mouseDownPosition.y);
      const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
      if (distance < this.DRAG_THRESHOLD)
        return;
      this.initializeDrag(this.pendingElement, this.pendingMouseOffset, e);
      this.mouseDownPosition = null;
      this.pendingElement = null;
      this.pendingMouseOffset = null;
    };
    this.handlePointerUp = (_e) => {
      this.mouseDownPosition = null;
      this.pendingElement = null;
      this.pendingMouseOffset = null;
      if (!this.dragState)
        return;
      cancelAnimationFrame(this.dragState.animationId);
      if (this.dragState.dragSource === "header") {
        this.handleHeaderItemDragEnd();
      } else {
        this.handleGridEventDragEnd();
      }
      this.dragState.element.classList.remove("dragging");
      this.dragState = null;
      this.inHeader = false;
    };
    this.animateDrag = () => {
      if (!this.dragState)
        return;
      const diff2 = this.dragState.targetY - this.dragState.currentY;
      if (Math.abs(diff2) <= 0.5) {
        this.dragState.animationId = 0;
        return;
      }
      this.dragState.currentY += diff2 * this.INTERPOLATION_FACTOR;
      this.dragState.element.style.top = `${this.dragState.currentY}px`;
      if (this.dragState.columnElement) {
        const payload = {
          eventId: this.dragState.eventId,
          element: this.dragState.element,
          currentY: this.dragState.currentY,
          columnElement: this.dragState.columnElement
        };
        this.eventBus.emit(CoreEvents.EVENT_DRAG_MOVE, payload);
      }
      this.dragState.animationId = requestAnimationFrame(this.animateDrag);
    };
    this.setupScrollListener();
  }
  setupScrollListener() {
    this.eventBus.on(CoreEvents.EDGE_SCROLL_TICK, (e) => {
      if (!this.dragState)
        return;
      const { scrollDelta } = e.detail;
      this.dragState.targetY += scrollDelta;
      this.dragState.currentY += scrollDelta;
      this.dragState.element.style.top = `${this.dragState.currentY}px`;
    });
  }
  /**
   * Initialize drag-drop on a container element
   */
  init(container) {
    this.container = container;
    container.addEventListener("pointerdown", this.handlePointerDown);
    document.addEventListener("pointermove", this.handlePointerMove);
    document.addEventListener("pointerup", this.handlePointerUp);
  }
  /**
   * Handle drag end for header items
   */
  handleHeaderItemDragEnd() {
    if (!this.dragState)
      return;
    if (!this.inHeader && this.dragState.currentColumn) {
      const gridEvent = this.dragState.currentColumn.querySelector(`swp-event[data-event-id="${this.dragState.eventId}"]`);
      if (gridEvent) {
        const columnKey = this.dragState.currentColumn.dataset.columnKey || "";
        const date = this.dragState.currentColumn.dataset.date || "";
        const swpEvent = SwpEvent.fromElement(gridEvent, columnKey, date, this.gridConfig);
        const payload = {
          swpEvent,
          sourceColumnKey: this.dragState.sourceColumnKey,
          target: "grid"
        };
        this.eventBus.emit(CoreEvents.EVENT_DRAG_END, payload);
      }
    }
  }
  /**
   * Handle drag end for grid events
   */
  handleGridEventDragEnd() {
    if (!this.dragState || !this.dragState.columnElement)
      return;
    const snappedY = snapToGrid(this.dragState.currentY, this.gridConfig);
    this.dragState.element.style.top = `${snappedY}px`;
    this.dragState.ghostElement?.remove();
    const columnKey = this.dragState.columnElement.dataset.columnKey || "";
    const date = this.dragState.columnElement.dataset.date || "";
    const swpEvent = SwpEvent.fromElement(this.dragState.element, columnKey, date, this.gridConfig);
    const payload = {
      swpEvent,
      sourceColumnKey: this.dragState.sourceColumnKey,
      target: this.inHeader ? "header" : "grid"
    };
    this.eventBus.emit(CoreEvents.EVENT_DRAG_END, payload);
  }
  initializeDrag(element, mouseOffset, e) {
    const eventId = element.dataset.eventId || "";
    const isHeaderItem = element.tagName.toLowerCase() === "swp-header-item";
    const columnElement = element.closest("swp-day-column");
    if (!isHeaderItem && !columnElement)
      return;
    if (isHeaderItem) {
      this.initializeHeaderItemDrag(element, mouseOffset, eventId);
    } else {
      this.initializeGridEventDrag(element, mouseOffset, e, columnElement, eventId);
    }
  }
  /**
   * Initialize drag for a header item (allDay event)
   */
  initializeHeaderItemDrag(element, mouseOffset, eventId) {
    element.classList.add("dragging");
    this.dragState = {
      eventId,
      element,
      ghostElement: null,
      // No ghost for header items
      startY: 0,
      mouseOffset,
      columnElement: null,
      currentColumn: null,
      targetY: 0,
      currentY: 0,
      animationId: 0,
      sourceColumnKey: "",
      // Will be set from header item data
      dragSource: "header"
    };
    this.inHeader = true;
  }
  /**
   * Initialize drag for a grid event
   */
  initializeGridEventDrag(element, mouseOffset, e, columnElement, eventId) {
    const elementRect = element.getBoundingClientRect();
    const columnRect = columnElement.getBoundingClientRect();
    const startY = elementRect.top - columnRect.top;
    const group = element.closest("swp-event-group");
    if (group) {
      const eventsLayer = columnElement.querySelector("swp-events-layer");
      if (eventsLayer) {
        eventsLayer.appendChild(element);
      }
    }
    element.style.position = "absolute";
    element.style.top = `${startY}px`;
    element.style.left = "2px";
    element.style.right = "2px";
    element.style.marginLeft = "0";
    const ghostElement = element.cloneNode(true);
    ghostElement.classList.add("drag-ghost");
    ghostElement.style.opacity = "0.3";
    ghostElement.style.pointerEvents = "none";
    element.parentNode?.insertBefore(ghostElement, element);
    element.classList.add("dragging");
    const targetY = e.clientY - columnRect.top - mouseOffset.y;
    this.dragState = {
      eventId,
      element,
      ghostElement,
      startY,
      mouseOffset,
      columnElement,
      currentColumn: columnElement,
      targetY: Math.max(0, targetY),
      currentY: startY,
      animationId: 0,
      sourceColumnKey: columnElement.dataset.columnKey || "",
      dragSource: "grid"
    };
    const payload = {
      eventId,
      element,
      ghostElement,
      startY,
      mouseOffset,
      columnElement
    };
    this.eventBus.emit(CoreEvents.EVENT_DRAG_START, payload);
    this.animateDrag();
  }
  updateDragTarget(e) {
    if (!this.dragState)
      return;
    this.checkHeaderZone(e);
    if (this.inHeader)
      return;
    const columnAtPoint = this.getColumnAtPoint(e.clientX);
    if (this.dragState.dragSource === "header" && columnAtPoint && !this.dragState.currentColumn) {
      this.dragState.currentColumn = columnAtPoint;
      this.dragState.columnElement = columnAtPoint;
    }
    if (columnAtPoint && columnAtPoint !== this.dragState.currentColumn && this.dragState.currentColumn) {
      const payload = {
        eventId: this.dragState.eventId,
        element: this.dragState.element,
        previousColumn: this.dragState.currentColumn,
        newColumn: columnAtPoint,
        currentY: this.dragState.currentY
      };
      this.eventBus.emit(CoreEvents.EVENT_DRAG_COLUMN_CHANGE, payload);
      this.dragState.currentColumn = columnAtPoint;
      this.dragState.columnElement = columnAtPoint;
    }
    if (!this.dragState.columnElement)
      return;
    const columnRect = this.dragState.columnElement.getBoundingClientRect();
    const targetY = e.clientY - columnRect.top - this.dragState.mouseOffset.y;
    this.dragState.targetY = Math.max(0, targetY);
    if (!this.dragState.animationId) {
      this.animateDrag();
    }
  }
  /**
   * Check if pointer is in header zone and emit appropriate events
   */
  checkHeaderZone(e) {
    if (!this.dragState)
      return;
    const headerViewport = document.querySelector("swp-header-viewport");
    if (!headerViewport)
      return;
    const rect = headerViewport.getBoundingClientRect();
    const isInHeader = e.clientY < rect.bottom;
    if (isInHeader && !this.inHeader) {
      this.inHeader = true;
      if (this.dragState.dragSource === "grid" && this.dragState.columnElement) {
        const payload = {
          eventId: this.dragState.eventId,
          element: this.dragState.element,
          sourceColumnIndex: this.getColumnIndex(this.dragState.columnElement),
          sourceColumnKey: this.dragState.columnElement.dataset.columnKey || "",
          title: this.dragState.element.querySelector("swp-event-title")?.textContent || "",
          colorClass: [...this.dragState.element.classList].find((c) => c.startsWith("is-")),
          itemType: "event",
          duration: 1
        };
        this.eventBus.emit(CoreEvents.EVENT_DRAG_ENTER_HEADER, payload);
      }
    } else if (!isInHeader && this.inHeader) {
      this.inHeader = false;
      const targetColumn = this.getColumnAtPoint(e.clientX);
      if (this.dragState.dragSource === "header") {
        const payload = {
          eventId: this.dragState.eventId,
          source: "header",
          element: this.dragState.element,
          targetColumn: targetColumn || void 0,
          start: this.dragState.element.dataset.start ? new Date(this.dragState.element.dataset.start) : void 0,
          end: this.dragState.element.dataset.end ? new Date(this.dragState.element.dataset.end) : void 0,
          title: this.dragState.element.textContent || "",
          colorClass: [...this.dragState.element.classList].find((c) => c.startsWith("is-"))
        };
        this.eventBus.emit(CoreEvents.EVENT_DRAG_LEAVE_HEADER, payload);
        if (targetColumn) {
          const newElement = targetColumn.querySelector(`swp-event[data-event-id="${this.dragState.eventId}"]`);
          if (newElement) {
            this.dragState.element = newElement;
            this.dragState.columnElement = targetColumn;
            this.dragState.currentColumn = targetColumn;
            this.animateDrag();
          }
        }
      } else {
        const payload = {
          eventId: this.dragState.eventId,
          source: "grid"
        };
        this.eventBus.emit(CoreEvents.EVENT_DRAG_LEAVE_HEADER, payload);
      }
    } else if (isInHeader) {
      const column = this.getColumnAtX(e.clientX);
      if (column) {
        const payload = {
          eventId: this.dragState.eventId,
          columnIndex: this.getColumnIndex(column),
          columnKey: column.dataset.columnKey || ""
        };
        this.eventBus.emit(CoreEvents.EVENT_DRAG_MOVE_HEADER, payload);
      }
    }
  }
  /**
   * Get column index (0-based) for a column element
   */
  getColumnIndex(column) {
    if (!this.container || !column)
      return 0;
    const columns = Array.from(this.container.querySelectorAll("swp-day-column"));
    return columns.indexOf(column);
  }
  /**
   * Get column at X coordinate (alias for getColumnAtPoint)
   */
  getColumnAtX(clientX) {
    return this.getColumnAtPoint(clientX);
  }
  /**
   * Find column element at given X coordinate
   */
  getColumnAtPoint(clientX) {
    if (!this.container)
      return null;
    const columns = this.container.querySelectorAll("swp-day-column");
    for (const col of columns) {
      const rect = col.getBoundingClientRect();
      if (clientX >= rect.left && clientX <= rect.right) {
        return col;
      }
    }
    return null;
  }
  /**
   * Cancel drag and animate back to start position
   */
  cancelDrag() {
    if (!this.dragState)
      return;
    cancelAnimationFrame(this.dragState.animationId);
    const { element, ghostElement, startY, eventId } = this.dragState;
    element.style.transition = "top 200ms ease-out";
    element.style.top = `${startY}px`;
    setTimeout(() => {
      ghostElement?.remove();
      element.style.transition = "";
      element.classList.remove("dragging");
    }, 200);
    const payload = {
      eventId,
      element,
      startY
    };
    this.eventBus.emit(CoreEvents.EVENT_DRAG_CANCEL, payload);
    this.dragState = null;
    this.inHeader = false;
  }
};
var EdgeScrollManager = class {
  constructor(eventBus) {
    this.eventBus = eventBus;
    this.scrollableContent = null;
    this.timeGrid = null;
    this.draggedElement = null;
    this.scrollRAF = null;
    this.mouseY = 0;
    this.isDragging = false;
    this.isScrolling = false;
    this.lastTs = 0;
    this.rect = null;
    this.initialScrollTop = 0;
    this.OUTER_ZONE = 100;
    this.INNER_ZONE = 50;
    this.SLOW_SPEED = 140;
    this.FAST_SPEED = 640;
    this.trackMouse = (e) => {
      if (this.isDragging) {
        this.mouseY = e.clientY;
      }
    };
    this.scrollTick = (ts) => {
      if (!this.isDragging || !this.scrollableContent)
        return;
      const dt = this.lastTs ? (ts - this.lastTs) / 1e3 : 0;
      this.lastTs = ts;
      this.rect ?? (this.rect = this.scrollableContent.getBoundingClientRect());
      const velocity = this.calculateVelocity();
      if (velocity !== 0 && !this.isAtBoundary(velocity)) {
        const scrollDelta = velocity * dt;
        this.scrollableContent.scrollTop += scrollDelta;
        this.rect = null;
        this.eventBus.emit(CoreEvents.EDGE_SCROLL_TICK, { scrollDelta });
        this.setScrollingState(true);
      } else {
        this.setScrollingState(false);
      }
      this.scrollRAF = requestAnimationFrame(this.scrollTick);
    };
    this.subscribeToEvents();
    document.addEventListener("pointermove", this.trackMouse);
  }
  init(scrollableContent) {
    this.scrollableContent = scrollableContent;
    this.timeGrid = scrollableContent.querySelector("swp-time-grid");
    this.scrollableContent.style.scrollBehavior = "auto";
  }
  subscribeToEvents() {
    this.eventBus.on(CoreEvents.EVENT_DRAG_START, (event) => {
      const payload = event.detail;
      this.draggedElement = payload.element;
      this.startDrag();
    });
    this.eventBus.on(CoreEvents.EVENT_DRAG_END, () => this.stopDrag());
    this.eventBus.on(CoreEvents.EVENT_DRAG_CANCEL, () => this.stopDrag());
  }
  startDrag() {
    this.isDragging = true;
    this.isScrolling = false;
    this.lastTs = 0;
    this.initialScrollTop = this.scrollableContent?.scrollTop ?? 0;
    if (this.scrollRAF === null) {
      this.scrollRAF = requestAnimationFrame(this.scrollTick);
    }
  }
  stopDrag() {
    this.isDragging = false;
    this.setScrollingState(false);
    if (this.scrollRAF !== null) {
      cancelAnimationFrame(this.scrollRAF);
      this.scrollRAF = null;
    }
    this.rect = null;
    this.lastTs = 0;
    this.initialScrollTop = 0;
  }
  calculateVelocity() {
    if (!this.rect)
      return 0;
    const distTop = this.mouseY - this.rect.top;
    const distBot = this.rect.bottom - this.mouseY;
    if (distTop < this.INNER_ZONE)
      return -this.FAST_SPEED;
    if (distTop < this.OUTER_ZONE)
      return -this.SLOW_SPEED;
    if (distBot < this.INNER_ZONE)
      return this.FAST_SPEED;
    if (distBot < this.OUTER_ZONE)
      return this.SLOW_SPEED;
    return 0;
  }
  isAtBoundary(velocity) {
    if (!this.scrollableContent || !this.timeGrid || !this.draggedElement)
      return false;
    const atTop = this.scrollableContent.scrollTop <= 0 && velocity < 0;
    const atBottom = velocity > 0 && this.draggedElement.getBoundingClientRect().bottom >= this.timeGrid.getBoundingClientRect().bottom;
    return atTop || atBottom;
  }
  setScrollingState(scrolling) {
    if (this.isScrolling === scrolling)
      return;
    this.isScrolling = scrolling;
    if (scrolling) {
      this.eventBus.emit(CoreEvents.EDGE_SCROLL_STARTED, {});
    } else {
      this.initialScrollTop = this.scrollableContent?.scrollTop ?? 0;
      this.eventBus.emit(CoreEvents.EDGE_SCROLL_STOPPED, {});
    }
  }
};
var ResizeManager = class {
  constructor(eventBus, gridConfig, dateService) {
    this.eventBus = eventBus;
    this.gridConfig = gridConfig;
    this.dateService = dateService;
    this.container = null;
    this.resizeState = null;
    this.Z_INDEX_RESIZING = "1000";
    this.ANIMATION_SPEED = 0.35;
    this.MIN_HEIGHT_MINUTES = 15;
    this.handleMouseOver = (e) => {
      const target = e.target;
      const eventElement = target.closest("swp-event");
      if (!eventElement || this.resizeState)
        return;
      if (!eventElement.querySelector(":scope > swp-resize-handle")) {
        const handle = this.createResizeHandle();
        eventElement.appendChild(handle);
      }
    };
    this.handlePointerDown = (e) => {
      const handle = e.target.closest("swp-resize-handle");
      if (!handle)
        return;
      const element = handle.parentElement;
      if (!element)
        return;
      const eventId = element.dataset.eventId || "";
      const startHeight = element.offsetHeight;
      const startDurationMinutes = pixelsToMinutes(startHeight, this.gridConfig);
      const container = element.closest("swp-event-group") ?? element;
      const prevZIndex = container.style.zIndex;
      this.resizeState = {
        eventId,
        element,
        handleElement: handle,
        startY: e.clientY,
        startHeight,
        startDurationMinutes,
        pointerId: e.pointerId,
        prevZIndex,
        // Animation state
        currentHeight: startHeight,
        targetHeight: startHeight,
        animationId: null
      };
      container.style.zIndex = this.Z_INDEX_RESIZING;
      try {
        handle.setPointerCapture(e.pointerId);
      } catch (err) {
        console.warn("Pointer capture failed:", err);
      }
      document.documentElement.classList.add("swp--resizing");
      this.eventBus.emit(CoreEvents.EVENT_RESIZE_START, {
        eventId,
        element,
        startHeight
      });
      e.preventDefault();
    };
    this.handlePointerMove = (e) => {
      if (!this.resizeState)
        return;
      const deltaY = e.clientY - this.resizeState.startY;
      const minHeight = this.MIN_HEIGHT_MINUTES / 60 * this.gridConfig.hourHeight;
      const newHeight = Math.max(minHeight, this.resizeState.startHeight + deltaY);
      this.resizeState.targetHeight = newHeight;
      if (this.resizeState.animationId === null) {
        this.animateHeight();
      }
    };
    this.animateHeight = () => {
      if (!this.resizeState)
        return;
      const diff2 = this.resizeState.targetHeight - this.resizeState.currentHeight;
      if (Math.abs(diff2) < 0.5) {
        this.resizeState.animationId = null;
        return;
      }
      this.resizeState.currentHeight += diff2 * this.ANIMATION_SPEED;
      this.resizeState.element.style.height = `${this.resizeState.currentHeight}px`;
      this.updateTimestampDisplay();
      this.resizeState.animationId = requestAnimationFrame(this.animateHeight);
    };
    this.handlePointerUp = (e) => {
      if (!this.resizeState)
        return;
      if (this.resizeState.animationId !== null) {
        cancelAnimationFrame(this.resizeState.animationId);
      }
      try {
        this.resizeState.handleElement.releasePointerCapture(e.pointerId);
      } catch (err) {
        console.warn("Pointer release failed:", err);
      }
      this.snapToGridFinal();
      this.updateTimestampDisplay();
      const container = this.resizeState.element.closest("swp-event-group") ?? this.resizeState.element;
      container.style.zIndex = this.resizeState.prevZIndex;
      document.documentElement.classList.remove("swp--resizing");
      const column = this.resizeState.element.closest("swp-day-column");
      const columnKey = column?.dataset.columnKey || "";
      const date = column?.dataset.date || "";
      const swpEvent = SwpEvent.fromElement(this.resizeState.element, columnKey, date, this.gridConfig);
      this.eventBus.emit(CoreEvents.EVENT_RESIZE_END, {
        swpEvent
      });
      this.resizeState = null;
    };
  }
  /**
   * Initialize resize functionality on container
   */
  init(container) {
    this.container = container;
    container.addEventListener("mouseover", this.handleMouseOver, true);
    document.addEventListener("pointerdown", this.handlePointerDown, true);
    document.addEventListener("pointermove", this.handlePointerMove, true);
    document.addEventListener("pointerup", this.handlePointerUp, true);
  }
  /**
   * Create resize handle element
   */
  createResizeHandle() {
    const handle = document.createElement("swp-resize-handle");
    handle.setAttribute("aria-label", "Resize event");
    handle.setAttribute("role", "separator");
    return handle;
  }
  /**
   * Update timestamp display with snapped end time
   */
  updateTimestampDisplay() {
    if (!this.resizeState)
      return;
    const timeEl = this.resizeState.element.querySelector("swp-event-time");
    if (!timeEl)
      return;
    const top = parseFloat(this.resizeState.element.style.top) || 0;
    const startMinutesFromGrid = pixelsToMinutes(top, this.gridConfig);
    const startMinutes = this.gridConfig.dayStartHour * 60 + startMinutesFromGrid;
    const snappedHeight = snapToGrid(this.resizeState.currentHeight, this.gridConfig);
    const durationMinutes = pixelsToMinutes(snappedHeight, this.gridConfig);
    const endMinutes = startMinutes + durationMinutes;
    const start = this.minutesToDate(startMinutes);
    const end = this.minutesToDate(endMinutes);
    timeEl.textContent = this.dateService.formatTimeRange(start, end);
  }
  /**
   * Convert minutes since midnight to Date
   */
  minutesToDate(minutes) {
    const date = /* @__PURE__ */ new Date();
    date.setHours(Math.floor(minutes / 60) % 24, minutes % 60, 0, 0);
    return date;
  }
  /**
   * Snap final height to grid interval
   */
  snapToGridFinal() {
    if (!this.resizeState)
      return;
    const currentHeight = this.resizeState.element.offsetHeight;
    const snappedHeight = snapToGrid(currentHeight, this.gridConfig);
    const minHeight = minutesToPixels(this.MIN_HEIGHT_MINUTES, this.gridConfig);
    const finalHeight = Math.max(minHeight, snappedHeight);
    this.resizeState.element.style.height = `${finalHeight}px`;
    this.resizeState.currentHeight = finalHeight;
  }
};
var EventPersistenceManager = class {
  constructor(eventService, eventBus, dateService) {
    this.eventService = eventService;
    this.eventBus = eventBus;
    this.dateService = dateService;
    this.handleDragEnd = async (e) => {
      const payload = e.detail;
      const { swpEvent } = payload;
      const event = await this.eventService.get(swpEvent.eventId);
      if (!event) {
        console.warn(`EventPersistenceManager: Event ${swpEvent.eventId} not found`);
        return;
      }
      const { resource } = this.dateService.parseColumnKey(swpEvent.columnKey);
      const updatedEvent = {
        ...event,
        start: swpEvent.start,
        end: swpEvent.end,
        resourceId: resource ?? event.resourceId,
        allDay: payload.target === "header",
        syncStatus: "pending"
      };
      await this.eventService.save(updatedEvent);
      const updatePayload = {
        eventId: updatedEvent.id,
        sourceColumnKey: payload.sourceColumnKey,
        targetColumnKey: swpEvent.columnKey
      };
      this.eventBus.emit(CoreEvents.EVENT_UPDATED, updatePayload);
    };
    this.handleResizeEnd = async (e) => {
      const payload = e.detail;
      const { swpEvent } = payload;
      const event = await this.eventService.get(swpEvent.eventId);
      if (!event) {
        console.warn(`EventPersistenceManager: Event ${swpEvent.eventId} not found`);
        return;
      }
      const updatedEvent = {
        ...event,
        end: swpEvent.end,
        syncStatus: "pending"
      };
      await this.eventService.save(updatedEvent);
      const updatePayload = {
        eventId: updatedEvent.id,
        sourceColumnKey: swpEvent.columnKey,
        targetColumnKey: swpEvent.columnKey
      };
      this.eventBus.emit(CoreEvents.EVENT_UPDATED, updatePayload);
    };
    this.setupListeners();
  }
  setupListeners() {
    this.eventBus.on(CoreEvents.EVENT_DRAG_END, this.handleDragEnd);
    this.eventBus.on(CoreEvents.EVENT_RESIZE_END, this.handleResizeEnd);
  }
};
var defaultTimeFormatConfig = {
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  use24HourFormat: true,
  locale: "da-DK",
  dateFormat: "locale",
  showSeconds: false
};
var defaultGridConfig = {
  hourHeight: 64,
  dayStartHour: 6,
  dayEndHour: 18,
  snapInterval: 15,
  gridStartThresholdMinutes: 30
};
function registerCoreServices(builder, options) {
  const timeConfig = options?.timeConfig ?? defaultTimeFormatConfig;
  const gridConfig = options?.gridConfig ?? defaultGridConfig;
  const dbConfig = options?.dbConfig ?? defaultDBConfig;
  builder.registerInstance(timeConfig).as("ITimeFormatConfig");
  builder.registerInstance(gridConfig).as("IGridConfig");
  builder.registerInstance(dbConfig).as("IDBConfig");
  builder.registerType(EventBus).as("EventBus");
  builder.registerType(EventBus).as("IEventBus");
  builder.registerType(DateService).as("DateService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("ITimeFormatConfig"),
      void 0
    ]
  });
  builder.registerType(IndexedDBContext).as("IndexedDBContext").autoWire({
    mapResolvers: [
      (c) => c.resolveTypeAll("IStore"),
      (c) => c.resolveType("IDBConfig")
    ]
  });
  builder.registerType(EventStore).as("IStore");
  builder.registerType(ResourceStore).as("IStore");
  builder.registerType(SettingsStore).as("IStore");
  builder.registerType(ViewConfigStore).as("IStore");
  builder.registerType(EventService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(EventService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(EventService).as("EventService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ResourceService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ResourceService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ResourceService).as("ResourceService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(SettingsService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(SettingsService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(SettingsService).as("SettingsService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ViewConfigService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ViewConfigService).as("IEntityService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ViewConfigService).as("ViewConfigService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(EventRenderer).as("EventRenderer").autoWire({
    mapResolvers: [
      (c) => c.resolveType("EventService"),
      (c) => c.resolveType("DateService"),
      (c) => c.resolveType("IGridConfig"),
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ScheduleRenderer).as("ScheduleRenderer").autoWire({
    mapResolvers: [
      (c) => c.resolveType("ResourceScheduleService"),
      (c) => c.resolveType("DateService"),
      (c) => c.resolveType("IGridConfig")
    ]
  });
  builder.registerType(HeaderDrawerRenderer).as("HeaderDrawerRenderer").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IEventBus"),
      (c) => c.resolveType("IGridConfig"),
      (c) => c.resolveType("HeaderDrawerManager"),
      (c) => c.resolveType("EventService"),
      (c) => c.resolveType("DateService")
    ]
  });
  builder.registerType(TimeAxisRenderer).as("TimeAxisRenderer");
  builder.registerType(DateRenderer).as("IRenderer").autoWire({
    mapResolvers: [
      (c) => c.resolveType("DateService")
    ]
  });
  builder.registerType(ResourceRenderer).as("IRenderer").autoWire({
    mapResolvers: [
      (c) => c.resolveType("ResourceService")
    ]
  });
  builder.registerType(ScrollManager).as("ScrollManager");
  builder.registerType(HeaderDrawerManager).as("HeaderDrawerManager");
  builder.registerType(DragDropManager).as("DragDropManager").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IEventBus"),
      (c) => c.resolveType("IGridConfig")
    ]
  });
  builder.registerType(EdgeScrollManager).as("EdgeScrollManager").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IEventBus")
    ]
  });
  builder.registerType(ResizeManager).as("ResizeManager").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IEventBus"),
      (c) => c.resolveType("IGridConfig"),
      (c) => c.resolveType("DateService")
    ]
  });
  builder.registerType(EventPersistenceManager).as("EventPersistenceManager").autoWire({
    mapResolvers: [
      (c) => c.resolveType("EventService"),
      (c) => c.resolveType("IEventBus"),
      (c) => c.resolveType("DateService")
    ]
  });
  builder.registerType(CalendarOrchestrator).as("CalendarOrchestrator").autoWire({
    mapResolvers: [
      (c) => c.resolveTypeAll("IRenderer"),
      (c) => c.resolveType("EventRenderer"),
      (c) => c.resolveType("ScheduleRenderer"),
      (c) => c.resolveType("HeaderDrawerRenderer"),
      (c) => c.resolveType("DateService"),
      (c) => c.resolveTypeAll("IEntityService")
    ]
  });
  builder.registerType(CalendarApp).as("CalendarApp").autoWire({
    mapResolvers: [
      (c) => c.resolveType("CalendarOrchestrator"),
      (c) => c.resolveType("TimeAxisRenderer"),
      (c) => c.resolveType("DateService"),
      (c) => c.resolveType("ScrollManager"),
      (c) => c.resolveType("HeaderDrawerManager"),
      (c) => c.resolveType("DragDropManager"),
      (c) => c.resolveType("EdgeScrollManager"),
      (c) => c.resolveType("ResizeManager"),
      (c) => c.resolveType("HeaderDrawerRenderer"),
      (c) => c.resolveType("EventPersistenceManager"),
      (c) => c.resolveType("SettingsService"),
      (c) => c.resolveType("ViewConfigService"),
      (c) => c.resolveType("IEventBus")
    ]
  });
}

// node_modules/calendar/dist/extensions/schedules/index.js
var ScheduleOverrideStore = class _ScheduleOverrideStore {
  constructor() {
    this.storeName = _ScheduleOverrideStore.STORE_NAME;
  }
  create(db) {
    const store = db.createObjectStore(_ScheduleOverrideStore.STORE_NAME, { keyPath: "id" });
    store.createIndex("resourceId", "resourceId", { unique: false });
    store.createIndex("date", "date", { unique: false });
    store.createIndex("resourceId_date", ["resourceId", "date"], { unique: true });
    store.createIndex("syncStatus", "syncStatus", { unique: false });
  }
};
ScheduleOverrideStore.STORE_NAME = "scheduleOverrides";
var ScheduleOverrideService = class {
  constructor(context) {
    this.context = context;
  }
  get db() {
    return this.context.getDatabase();
  }
  /**
   * Get override for a specific resource and date
   */
  async getOverride(resourceId, date) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([ScheduleOverrideStore.STORE_NAME], "readonly");
      const store = transaction.objectStore(ScheduleOverrideStore.STORE_NAME);
      const index = store.index("resourceId_date");
      const request = index.get([resourceId, date]);
      request.onsuccess = () => {
        resolve(request.result || null);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get override for ${resourceId} on ${date}: ${request.error}`));
      };
    });
  }
  /**
   * Get all overrides for a resource
   */
  async getByResource(resourceId) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([ScheduleOverrideStore.STORE_NAME], "readonly");
      const store = transaction.objectStore(ScheduleOverrideStore.STORE_NAME);
      const index = store.index("resourceId");
      const request = index.getAll(resourceId);
      request.onsuccess = () => {
        resolve(request.result || []);
      };
      request.onerror = () => {
        reject(new Error(`Failed to get overrides for ${resourceId}: ${request.error}`));
      };
    });
  }
  /**
   * Get overrides for a date range
   */
  async getByDateRange(resourceId, startDate, endDate) {
    const all = await this.getByResource(resourceId);
    return all.filter((o) => o.date >= startDate && o.date <= endDate);
  }
  /**
   * Save an override
   */
  async save(override) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([ScheduleOverrideStore.STORE_NAME], "readwrite");
      const store = transaction.objectStore(ScheduleOverrideStore.STORE_NAME);
      const request = store.put(override);
      request.onsuccess = () => resolve();
      request.onerror = () => {
        reject(new Error(`Failed to save override ${override.id}: ${request.error}`));
      };
    });
  }
  /**
   * Delete an override
   */
  async delete(id) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([ScheduleOverrideStore.STORE_NAME], "readwrite");
      const store = transaction.objectStore(ScheduleOverrideStore.STORE_NAME);
      const request = store.delete(id);
      request.onsuccess = () => resolve();
      request.onerror = () => {
        reject(new Error(`Failed to delete override ${id}: ${request.error}`));
      };
    });
  }
};
var ResourceScheduleService = class {
  constructor(resourceService, overrideService, dateService) {
    this.resourceService = resourceService;
    this.overrideService = overrideService;
    this.dateService = dateService;
  }
  /**
   * Get effective schedule for a resource on a specific date
   *
   * @param resourceId - Resource ID
   * @param date - Date string "YYYY-MM-DD"
   * @returns ITimeSlot or null (fri/closed)
   */
  async getScheduleForDate(resourceId, date) {
    const override = await this.overrideService.getOverride(resourceId, date);
    if (override) {
      return override.schedule;
    }
    const resource = await this.resourceService.get(resourceId);
    if (!resource || !resource.defaultSchedule) {
      return null;
    }
    const weekDay = this.dateService.getISOWeekDay(date);
    return resource.defaultSchedule[weekDay] || null;
  }
  /**
   * Get schedules for multiple dates
   *
   * @param resourceId - Resource ID
   * @param dates - Array of date strings "YYYY-MM-DD"
   * @returns Map of date -> ITimeSlot | null
   */
  async getSchedulesForDates(resourceId, dates) {
    const result = /* @__PURE__ */ new Map();
    const resource = await this.resourceService.get(resourceId);
    const overrides = dates.length > 0 ? await this.overrideService.getByDateRange(resourceId, dates[0], dates[dates.length - 1]) : [];
    const overrideMap = new Map(overrides.map((o) => [o.date, o.schedule]));
    for (const date of dates) {
      if (overrideMap.has(date)) {
        result.set(date, overrideMap.get(date));
        continue;
      }
      if (resource?.defaultSchedule) {
        const weekDay = this.dateService.getISOWeekDay(date);
        result.set(date, resource.defaultSchedule[weekDay] || null);
      } else {
        result.set(date, null);
      }
    }
    return result;
  }
};
function registerSchedules(builder) {
  builder.registerType(ScheduleOverrideStore).as("IStore");
  builder.registerType(ScheduleOverrideService).as("ScheduleOverrideService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("IndexedDBContext")
    ]
  });
  builder.registerType(ResourceScheduleService).as("ResourceScheduleService").autoWire({
    mapResolvers: [
      (c) => c.resolveType("ResourceService"),
      (c) => c.resolveType("ScheduleOverrideService"),
      (c) => c.resolveType("DateService")
    ]
  });
}

// src/index.ts
async function init() {
  const databases = await indexedDB.databases();
  const dbExists = databases.some((db) => db.name === "CalendarTestDB");
  const container = new Container();
  const builder = container.builder();
  registerCoreServices(builder, {
    dbConfig: { dbName: "CalendarTestDB", dbVersion: 4 }
  });
  registerSchedules(builder);
  const app = builder.build();
  console.log("Container created");
  const dbContext = app.resolveType("IndexedDBContext");
  await dbContext.initialize();
  console.log("IndexedDB initialized");
  const settingsService = app.resolveType("SettingsService");
  const viewConfigService = app.resolveType("ViewConfigService");
  const eventService = app.resolveType("EventService");
  if (dbExists) {
    console.log("Database exists, skipping seed");
  } else {
    console.log("Seeding data...");
    await seedData(settingsService, viewConfigService, eventService);
  }
  const calendarApp = app.resolveType("CalendarApp");
  const containerEl = document.querySelector("swp-calendar-container");
  await calendarApp.init(containerEl);
  const eventBus = app.resolveType("EventBus");
  eventBus.emit(CalendarEvents.CMD_RENDER, { viewId: "simple" });
  console.log("Calendar rendered");
  document.addEventListener("event:drag-end", (e) => {
    console.log("event:drag-end:", e.detail);
  });
  document.addEventListener("event:updated", (e) => {
    console.log("event:updated:", e.detail);
  });
  const persistenceManager = app.resolveType("EventPersistenceManager");
  console.log("EventPersistenceManager resolved:", persistenceManager);
}
async function seedData(settingsService, viewConfigService, eventService) {
  await settingsService.save({
    id: "grid",
    dayStartHour: 8,
    dayEndHour: 17,
    workStartHour: 9,
    workEndHour: 16,
    hourHeight: 64,
    snapInterval: 15,
    syncStatus: "synced"
  });
  await settingsService.save({
    id: "workweek",
    presets: {
      standard: { id: "standard", label: "Standard", workDays: [1, 2, 3, 4, 5], periodDays: 7 }
    },
    defaultPreset: "standard",
    firstDayOfWeek: 1,
    syncStatus: "synced"
  });
  await viewConfigService.save({
    id: "simple",
    groupings: [{ type: "date", values: [], idProperty: "date", derivedFrom: "start" }],
    syncStatus: "synced"
  });
  const today = /* @__PURE__ */ new Date();
  today.setHours(0, 0, 0, 0);
  console.log("Event date:", today.toISOString());
  const start1 = new Date(today);
  start1.setHours(9, 0, 0, 0);
  const end1 = new Date(today);
  end1.setHours(10, 0, 0, 0);
  await eventService.save({
    id: "1",
    title: "Morgenm\xF8de",
    start: start1,
    end: end1,
    type: "meeting",
    allDay: false,
    syncStatus: "synced"
  });
  const start2 = new Date(today);
  start2.setHours(12, 0, 0, 0);
  const end2 = new Date(today);
  end2.setHours(13, 0, 0, 0);
  await eventService.save({
    id: "2",
    title: "Frokost",
    start: start2,
    end: end2,
    type: "break",
    allDay: false,
    syncStatus: "synced"
  });
}
init().catch(console.error);
