{ pkgs, hyper, ... }@all: with all; let 
  radicale-root = "/var/lib/radicale";
  web-root = "/var/nginx/webroot";
in {
  systemd.timers."nx_cal_publish" = {
    enable = true;
    wantedBy = [ "timers.target" ];
    timerConfig = {
      OnBootSec = "2m";
      OnUnitActiveSec = "6h";
      Unit = "nx_cal_publish.service";
    };
  };

  systemd.services."nx_cal_publish" = {
    script = with pkgs; let 
      nx_cal_publish = (writers.writePython3Bin "nx_cal_publish" {
        libraries = with python3Packages; [ 
          ical
          ics
          requests
          dateutils
        ];
        flakeIgnore = [ "E302" "E305" "E226" "E501" ];
      } /*python */ ''
import pytz
import os
from ics import Calendar, Event
from ics.grammar.parse import ContentLine
from dateutil.rrule import rrulestr
from ics.event import datetime, timedelta

def combine_ics_from_directories(directories, output_file):
    """
    Combine all .ics events from a list of directories into one .ics file, supporting recurring events.

    :param directories: List of directories containing .ics files.
    :param output_file: Path to the output .ics file.
    """
    combined_calendar = Calendar()

    for directory in directories:
        if not os.path.exists(directory):
            print(f"Directory '{directory}' does not exist. Skipping.")
            continue

        for filename in os.listdir(directory):
            if filename.endswith(".ics"):
                file_path = os.path.join(directory, filename)
                try:
                    with open(file_path, 'r') as file:
                        calendar = Calendar(file.read())
                        for event in calendar.events:
                            # Handle recurring events
                            rrule_line = None
                            for line in event.extra:
                                if isinstance(line, ContentLine) and line.name == "RRULE":
                                    rrule_line = line
                                    break

                            if rrule_line:
                                # Convert UNTIL to UTC if DTSTART is timezone-aware
                                rrule_params = rrule_line.value.split(";")
                                rrule_dict = {}
                                for param in rrule_params:
                                    key, value = param.split("=")
                                    rrule_dict[key] = value

                                if "UNTIL" in rrule_dict and event.begin.tzinfo:
                                    until = datetime.fromisoformat(rrule_dict["UNTIL"])
                                    if until.tzinfo is None:  # If UNTIL is naive, make it UTC
                                        until = until.astimezone(pytz.UTC)
                                    rrule_dict["UNTIL"] = until.astimezone(pytz.UTC).strftime("%Y%m%dT%H%M%SZ")

                                # Reconstruct RRULE string
                                rrule_fixed = ";".join(f"{key}={value}" for key, value in rrule_dict.items())
                                rrule = rrulestr(rrule_fixed, dtstart=event.begin.astimezone(pytz.timezone('CET')))

                                # Expand recurring events and filter based on the date
                                for occurrence in rrule:
                                    notTooOld = occurrence.date() >= (datetime.now().astimezone(pytz.UTC) - timedelta(days=1)).date()
                                    notTooFuturisic = occurrence.date() < (datetime.now().astimezone(pytz.UTC) + timedelta(days=60)).date()
                                    if notTooOld and notTooFuturisic:
                                        new_event = Event(
                                            name="",
                                            begin=occurrence,
                                            end=occurrence + (event.end - event.begin),
                                            transparent=event.transparent or True,
                                        )
                                        combined_calendar.events.add(new_event)
                            else:
                                # Regular events, directly add if within date range
                                if event.begin.astimezone(pytz.timezone('CET')).date() >= (datetime.now().astimezone(pytz.timezone('CET')) - timedelta(days=1)).date():
                                    new_event = Event(
                                        name="",
                                        begin=event.begin,
                                        end=event.end,
                                        transparent=event.transparent or True,
                                    )
                                    combined_calendar.events.add(new_event)

                except Exception as e:
                    print(f"Error reading file '{file_path}': {e}")
                    exit(1)

    try:
        with open(output_file, 'w') as file:
            file.writelines(combined_calendar.serialize_iter())
        print(f"Combined .ics file saved to '{output_file}'")
    except Exception as e:
        print(f"Error saving combined .ics file: {e}")

if __name__ == "__main__":
    # List of directories containing .ics files
    DIRECTORIES = [
        "${radicale-root}/collections/collection-root/${hyper.user}/preservation",
        "${radicale-root}/collections/collection-root/${hyper.user}/effort",
        "${radicale-root}/collections/collection-root/${hyper.user}/experience",
        "${radicale-root}/collections/collection-root/${hyper.user}/exposure",
        "${radicale-root}/collections/collection-root/${hyper.user}/engagement",
    ]

    # Path to the output .ics file
    OUTPUT_FILE = "${web-root}/schedule.ics"

    combine_ics_from_directories(DIRECTORIES, OUTPUT_FILE)
''); 
    in ''
      ${nx_cal_publish}/bin/nx_cal_publish
    '';
    serviceConfig = {
      Type = "oneshot";
      User = hyper.user;
    };
  };
}
