{ pkgs, ... }@all: with all;
  sep = " ";
in {
  home = {
    file."${config.xdg.dataHome}/nx-gcal-event-credentials.json".text = ''
      {
        "installed": {
          "client_id": "${secrets.nx-gcal-event.client-client-id}",
          "project_id": "my-own-cal",
          "auth_uri": "https://accounts.google.com/o/oauth2/auth",
          "token_uri": "https://oauth2.googleapis.com/token",
          "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
          "client_secret": "${secrets.nx-gcal-event.client-secret}",
          "redirect_uris": [
            "http://localhost"
          ]
        }
      }
    '';

    packages = with pkgs; [
      # TODO: make into real package, currently dependencies are in home.nix
      # (pkgs.python311.withPackages (python-pkgs: [
      #   python-pkgs.google
      # ]))
      (writeScriptBin "nx_gcal_event" /* python */ ''
        #!${pkgs.python3}/bin/python3
        import datetime
        import os
        import pickle
        import sys

        from google.auth.transport.requests import Request
        from google.oauth2.credentials import Credentials
        from google_auth_oauthlib.flow import InstalledAppFlow
        from googleapiclient.discovery import build
        from googleapiclient.errors import HttpError
        from html import escape



        CREDENTIALS_PATH = f"{os.environ['XDG_DATA_HOME']}/nx-gcal-event-credentials.json"
        TOKEN_PATH        = f"{os.environ['XDG_CACHE_HOME']}/nx-gcal-event-token.json"
        PICKLE_PATH       = "/tmp/nx-gcal-event.pickle"


        def sec_to_nice_string(seconds: int):
            (hours, rsec) = divmod(seconds, 3600)
            minutes = rsec // 60
            sep = " "
            if hours == 0:
                s_hours = f""
                sep = ""
            elif hours == 1: s_hours = f"{hours} hour"
            else: s_hours = f"{hours} hours"
            if minutes == 0:
                s_minutes = f""
                sep = ""
            elif minutes == 1: s_minutes = f"{minutes} minute"
            else: s_minutes = f"{minutes} minutes"
            if hours + minutes == 0:
                s_minutes = "~ No time"
                os.remove(PICKLE_PATH)

            return f"{s_hours}{sep}{s_minutes}"

        def get_event_from_api():
            creds = None
            SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]

            if os.path.exists(TOKEN_PATH):
                creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
                    
            if not creds or not creds.valid:    
                if creds and creds.expired and creds.refresh_token:
                    creds.refresh(Request())
                else:
                    flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_PATH, SCOPES)
                    creds = flow.run_local_server(port=0)
                # Save the credentials for the next run
                with open(TOKEN_PATH, "w") as token:
                    token.write(creds.to_json())

            try:
                service = build("calendar", "v3", credentials=creds)
                now = datetime.datetime.utcnow().isoformat() + "Z"  # 'Z' indicates UTC time
                in_24_h = (datetime.datetime.utcnow() + datetime.timedelta(days=1)).isoformat() + "Z"
                calendar_list = service.calendarList().list().execute()
                calendars = calendar_list.get("items", [])

                # List events from all calendars
                all_events = []
                for calendar in calendars:
                    calendar_id = calendar["id"]
                    events_result = service.events().list(
                        calendarId=calendar_id,
                        timeMin=now,
                        timeMax=in_24_h,
                        singleEvents=True,
                        orderBy="startTime",
                    ).execute()
                    events = events_result.get("items", [])

                    all_events.extend(events)

                # Filter out all-day events
                all_events = [event for event in all_events if "dateTime" in event["start"]]

                # Find the earliest event
                earliest_event = None
                for event in all_events:
                    event_start = event["start"]["dateTime"]
                    if not earliest_event or event_start < earliest_event["start"]["dateTime"]:
                        earliest_event = event

                # Now earliest_event contains the event that starts earliest
                return earliest_event   

            except HttpError as error:
                print("An error occurred: %s" % error)
                exit(1)

        def dump_dict_to_file(event, now):
            if not event:
                event = {}
            event['nxWriteTime'] = now
            with open(PICKLE_PATH, 'wb') as f:
                pickle.dump(event, f)

        def load_dict_from_file(now):
            with open(PICKLE_PATH, 'rb') as f:
                event = pickle.load(f)
            # recheck all 15 minutes
            if (now - event['nxWriteTime']).seconds > 900: 
                event = get_event_from_api()
                os.remove(PICKLE_PATH)
            return event

        def lookup():
                # set now (timezone CEST)
                now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=2)))

                no_event_string = "~ Zen ~"

                if os.path.exists(PICKLE_PATH):
                    event = load_dict_from_file(now)
                else:
                    event = get_event_from_api()
                    if not event:
                        print(no_event_string)
                        dump_dict_to_file(event, now)
                        exit(0)
                    dump_dict_to_file(event, now)
                
                try: # when the saved even was empty (there was no event)
                    end = datetime.datetime.strptime(event["end"]["dateTime"], "%Y-%m-%dT%H:%M:%S%z")
                    start = datetime.datetime.strptime(event["start"]["dateTime"], "%Y-%m-%dT%H:%M:%S%z")
                except:
                    if (now - event['nxWriteTime']).seconds > 900: 
                        event = get_event_from_api()
                        os.remove(PICKLE_PATH)
                    else:
                        print(no_event_string)
                        exit(0)

                # set mode, remaining
                if start.day != now.day:     # event start tomorrow
                    print(no_event_string)
                    exit(0)
                elif (start - now).days < 0: # today, started alredy
                    remaining = end - now
                    mode = " remaining in "
                else:                        # today, not started yet
                    remaining = start - now
                    mode = " until the start of "

                name = escape(event['summary'])

                print(f"󱙬${sep}{sec_to_nice_string(remaining.seconds)}{mode}\'{name}\'")
                exit(0)

        def print_help():
            print("Usage: nx_gcal_event [lookup|force-lookup|reauthenicate|help]")

        def forece_lookup():
            try:
                os.remove(PICKLE_PATH)
                os.system('notify-send --app-name="nx_gcal_event" "Saved event deleted!"')
            except:
                os.system('notify-send --app-name="nx_gcal_event" "No saved event found!"')
            finally:
                lookup()

        def reauthenicate():
            try:
                os.remove(PICKLE_PATH)
                os.remove(TOKEN_PATH)
                os.system('notify-send --app-name="nx_gcal_event" "Deleted Token"')
            exept: 
                lookup()

        def print_help():
            print("Usage: nx_gcal_event [lookup|force-lookup|reauthenicate|help]")

        if __name__ == "__main__":
            if len(sys.argv) != 2:
                print("Incorrect number of arguments.")
                print_help()
            else:
                arg = sys.argv[1]
                if arg == "lookup":
                    lookup()
                elif arg == "force-lookup":
                    forece_lookup()
                elif arg == "reauthenticate":
                    reauthenicate()
                elif arg == "help":
                    print_help()
                else:
                    print_help()
      '')
    ];
  };
}
