// index.ts
function normalizeUrl(url) {
  if (!/^https?:\/\//i.test(url)) {
    return "https://" + url;
  }
  return url;
}
var index_default = ({ log, db, services }) => ({
  settings: {},
  manifest: {
    name: "Feed",
    author: "lesion",
    url: "https://framagit.org/les/gancio",
    description: "Get events from a specified ICS feed: you can specify only a single feed, images are not imported from ics, event location are taken as is as are not structured in ICS",
    settings: {
      refresh_minutes: {
        type: "NUMBER",
        description: "Refresh the feed each N minutes, if 0 refreshes only at startup",
        required: true,
        hint: "60 minutes?"
      },
      feed_URL: {
        type: "TEXT",
        description: "ICS feed URL",
        required: true,
        hint: "Check it before"
      },
      include_past: {
        type: "CHECK",
        description: "Include events in the past",
        required: true
      },
      add_tag: {
        type: "TEXT",
        description: "Add tag(s) to each imported event (comma-separated)",
        required: false
      }
    }
  },
  load() {
    log.debug("Feed plugin loaded with settings:", this.settings);
    services.TaskManager.add({
      name: "Plugin:Feed",
      repeat: true,
      repeatDelay: Number(this.settings?.refresh_minutes),
      method: async () => {
        try {
          await this._tick(normalizeUrl(this.settings?.feed_URL), this.settings?.add_tag, this.settings?.include_past);
        } catch (e) {
          log.error(`[FEED Plugin] Error in scheduled refresh: ${String(e)}`);
        }
      }
    });
  },
  unload() {
    log.debug("Feed plugin unloaded");
    services.TaskManager.remove("Plugin:Feed");
  },
  routeAPI() {
    log.debug("routeAPI called");
    return { success: true };
  },
  async onCLI(args) {
    log.debug("onCLI called with args:", args);
    if (args[0] === "refresh") {
      const ret = await this._tick(this.settings?.feed_URL, [], this.settings?.include_past);
      console.log("Feed refreshed", ret);
    }
    if (args[0] === "listSources") {
      console.log([{ feed_URL: this.settings?.feed_URL, include_past: this.settings?.include_past }]);
    }
  },
  onTest(settings) {
    if (!settings.feed_URL) {
      throw Error("feed_URL is required");
    }
    const ret = this._tick(normalizeUrl(settings.feed_URL), settings.add_tag, false);
    return ret;
  },
  _isTickRunning: false,
  etag: null,
  lastModified: null,
  async _tick(feed_URL, defaultTags, includePastEvents) {
    if (this._isTickRunning) {
      log.warn("[FEED Plugin] _tick already in progress, skipping");
      throw Error("[Feed Plugin] Already working");
    }
    if (!feed_URL) {
      log.warn("[FEED Plugin] feed URL is required!");
      throw Error("[Feed Plugin] feed URL is required");
    }
    try {
      log.debug("[FEED Plugin] _tick started, locking it");
      this._isTickRunning = true;
      const add_tags = defaultTags?.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
      let tags;
      if (add_tags?.length) {
        log.debug(`[FEED Plugin] Adding tags to imported events: ${add_tags}`);
        tags = await services.findOrCreateTags(add_tags);
      }
      const headers = {
        Accept: "text/calendar",
        ...this.lastModified && { "If-Modified-Since": this.lastModified },
        ...this.etag && { "If-None-Match": this.etag }
      };
      log.debug(`[FEED Plugin] Fetching ${feed_URL} with headers: ${JSON.stringify(headers)}`);
      const ret = await fetch(feed_URL, { headers });
      if (ret.status === 304) {
        log.debug("[FEED Plugin] Feed not modified, skipping");
        return;
      }
      if (!ret.ok) {
        log.error(`[FEED Plugin] Failed to fetch feed: ${ret.status} ${ret.statusText}`);
        throw Error(`Failed to fetch feed: ${ret.status} ${ret.statusText}`);
      }
      this.etag = ret.headers.get("ETag");
      this.lastModified = ret.headers.get("Last-Modified");
      log.debug(`[FEED Plugin] Updated feed metadata: ETag=${this.etag}, Last-Modified=${this.lastModified}`);
      const icsText = await ret.text();
      const events = services.parseIcsData(icsText, includePastEvents);
      log.info(`Found ${events.length} event(s)`);
      for (const evt of events) {
        if (!evt) continue;
        const exists = await db.Event.findOne({
          where: {
            title: evt?.title,
            start_datetime: evt?.start_datetime
          }
        });
        if (exists) {
          log.debug(`[FEED Plugin] Event ${evt.title} already exists, do not add it`);
          continue;
        }
        log.debug(`[FEED Plugin] Adding event: ${evt.title} `);
        const loc = evt.location?.trim();
        const pos = loc?.indexOf(",");
        const placeName = loc?.substring(0, pos === -1 ? void 0 : pos).trim() || "Unknown Place";
        const address = loc?.substring(pos === -1 ? 0 : pos + 1).trim() || placeName;
        try {
          let place = await db.Place.findOne({ where: { name: placeName } });
          if (place) {
            log.debug(`[FEED Plugin] Place ${place.name} already exists, do not add it`);
          } else {
            log.debug(`[FEED Plugin] Create a new place: ${placeName}`);
            place = await db.Place.create({ name: placeName, address });
          }
          const dbEvent = await db.Event.create(evt);
          await dbEvent.setPlace(place);
          await dbEvent.setTags(tags);
          log.info(`[FEED Plugin] Created event ${dbEvent.title} @ ${place.name}`);
        } catch (e) {
          log.error(`[FEED Plugin] Error creating event: ${String(e)}`);
        }
      }
    } catch (e) {
      log.error(e);
      throw e;
    } finally {
      log.debug("[FEED Plugin] _tick finished, unlocking it");
      this._isTickRunning = false;
    }
  }
});
export {
  index_default as default
};
