{ pkgs, lib, config, ... }:
let

  unstable = import <nixpkgs-unstable> { };

  networkStatus = let

    q-online = ''
      if ${pkgs.curl}/bin/curl -s google.com >/dev/null; then
        echo 'status: online'
      else
        echo 'status: offline '
      fi
    '';

    q-wireless = ''
      for dev in $(
        ${pkgs.iw}/bin/iw dev \
          | ${pkgs.gnused}/bin/sed -n 's/^\s*Interface\s\+\([0-9a-z]\+\)$/\1/p'
      ); do
        inet=$(${pkgs.iproute}/bin/ip addr show $dev \
          | ${pkgs.gnused}/bin/sed -n 's/.*inet \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p') \
          || unset inet
        ssid=$(${pkgs.iw}/bin/iw dev $dev link \
          | ${pkgs.gnused}/bin/sed -n 's/.*\tSSID: \(.*\)/\1/p' \
          | ${pkgs.coreutils}/bin/tr -d '\r') \
          || unset ssid
        printf '%s: %s %s\n' $dev ''${inet+ $inet} ''${ssid+ $ssid}
      done
    '';

  in pkgs.writers.writeBash "network-status" ''
    ${q-wireless}
    ${q-online}
    ${pkgs.coreutils}/bin/uptime
  '';

  taskNextWeek = pkgs.writers.writeDash "taskweek" ''
    ${pkgs.taskwarrior}/bin/task \
                        export \
                        status:pending and \( due.before:7days and due.after:today \) \
        | ${pkgs.jq}/bin/jq '[.[] | { Day: .due, ID: .id, Description: .description | sub("\n.*";"")} ] | sort_by(.Day)' \
        | ${pkgs.miller}/bin/mlr --ijson --opprint put '$Day = strftime(strptime($Day,"%Y%m%dT%H%M%SZ")'$(date +%z)'00,"%a")'
  '';

  activeTasks = pkgs.writers.writeBash "active-tasks" ''
    ${pkgs.taskwarrior}/bin/task export +checklist status:pending +READY | \
    ${pkgs.jq}/bin/jq  \
      --raw-output '
      sort_by(.description) | reverse |
      .[] |
      "[ \( .id ) ] \( .description )"
    '
    echo
    ${pkgs.taskwarrior}/bin/task export  \
    +ACTIVE status:pending \
    | ${pkgs.jq}/bin/jq --raw-output '.[] | "⇒ \(.id) \(.description)"'
  '';

  userHighlight = map ({ user, ... }: user)
    (builtins.attrValues config.programs.custom.browser.configList)
    ++ [ "steam" ];

  activeUsers = pkgs.writers.writeBash "active-users" ''
    ${pkgs.procps}/bin/ps -eo user \
     | ${pkgs.gnused}/bin/sed '1 d' \
     | ${pkgs.coreutils}/bin/sort  \
     | ${pkgs.coreutils}/bin/uniq \
     | ${pkgs.gnugrep}/bin/egrep --color=always '(${
       pkgs.lib.concatStringsSep "|" userHighlight
     })|$'
  '';

  # default settings
  wtfModule =
    args@{ height ? 1, width ? 1, top, left, enabled ? true, type, ... }:
    {
      enabled = enabled;
      focusable = false;
      position.top = top;
      position.left = left;
      position.height = height;
      position.width = width;
    } // (lib.filterAttrs
      (key: _: lib.all (x: x != key) [ "height" "width" "top" "left" ]) args);

  # command runner module
  cmdRunner = args@{ cmd, ... }:
    wtfModule ({
      type = "cmdrunner";
      focusable = false;
      refreshInterval = 300;
    } // args);

  modules = {
    inherit cmdRunner;

    # not working: had no time to investigate
    #digitalclock = args@{ top, left, ... }:
    #  wtfModule ({
    #    type = "digitalclock";
    #    title = "";
    #    color = "white";
    #    font = "bigfont";
    #    hourFormat = 24;
    #    refreshInterval = 1;
    #  } // args);

    digitalclock = args@{ top, left, ... }:
      cmdRunner ({
        cmd = pkgs.writers.writeDash "clock" ''
          ${pkgs.toilet}/bin/toilet --font future `${pkgs.coreutils}/bin/date +"%a %H:%M"`
          ${pkgs.coreutils}/bin/date +"%B %d %Y"
        '';
        title = "";
        refreshInterval = 30;
      } // args);

    clocks = args@{ top, left, ... }:
      wtfModule ({
        type = "clocks";
        title = "";
        border = false;
        colors.rows = {
          even = "white";
          odd = "white";
        };
        locations = {
          Berlin = "Europe/Berlin";
          Wellington = "Pacific/Auckland";
        };
        sort = "alphabetical";
        refreshInterval = 60;
      } // args);

    resourceusage = args@{ top, left, ... }:
      wtfModule ({
        type = "resourceusage";
        title = "";
        cpuCombined = false;
        refreshInterval = 5;
      } // args);

    power = args@{ top, left, ... }:
      wtfModule ({
        type = "power";
        title = "";
        refreshInterval = 100;
      } // args);

    prettyweather = args@{ top, left, ... }:
      wtfModule ({
        type = "prettyweather";
        title = "";
        city = "Wellington";
        unit = "m";
        view = 0;
        language = "en";
        refreshInterval = 3600;
      } // args);

    feedreader = args@{ top, left, feeds, ... }:
      wtfModule ({
        type = "feedreader";
        title = "";
        refreshInterval = 3600;
        focusable = true;
        #feedLimit = 10;
        colors.rows = {
          even = "white";
          odd = "white";
        };
      } // args);

    github = args@{ top, left, username, apiKey, ... }:
      wtfModule ({
        type = "github";
        title = "";
        refreshInterval = 3600;
        feedlimit = 10;

        enableStatus = true;
        #  customQueries:
        #    othersPRs:
        #      title: "Others Pull Requests"
        #      filter: "is:open is:pr -author:wtfutil"
        #  repositories:
        #    - "wtfutil/wtf"
        #    - "wtfutil/docs"
        #    - "umbrella-corp/wesker-api"
      } // args);

  };

  newsJson = {
    wtf = {
      term = "rxvt-unicode-256color";
      colors.border = {
        focusable = "darkslateblue";
        focused = "orange";
        normal = "green";
      };
      grid = {
        columns = [ 28 0 0 ];
        rows = [ 9 9 9 9 9 9 0 ];
      };
      refreshInterval = 1;
      mods = with modules; {

        clock = digitalclock {
          top = 0;
          left = 0;
        };
        weather = prettyweather {
          top = 1;
          left = 0;
        };

        # feeds
        hackernews = feedreader {
          title = "Hacker News";
          top = 0;
          left = 1;
          height = 3;
          feeds = [ "https://news.ycombinator.com/rss" ];
        };
        lopster = feedreader {
          title = "Lopsters";
          top = 0;
          left = 2;
          height = 3;
          feeds = [ "https://lobste.rs/rss" ];
        };

        hackernews_tools = feedreader {
          title = "Hacker News Tools";
          top = 4;
          left = 1;
          height = 1;
          feeds =
            [ "https://latesthackingnews.com/category/hacking-tools/feed/" ];
        };
        nixos = feedreader {
          title = "NixOS Weekly";
          top = 3;
          left = 1;
          height = 1;
          feeds = [ "https://weekly.nixos.org/feeds/all.rss.xml" ];
        };
        taskwarrior = feedreader {
          title = "Taskwarrior";
          top = 3;
          left = 2;
          height = 1;
          feeds = [ "https://taskwarrior.org/feed.rss" ];
        };

        #github = github {
        #  username = "mrVanDalo";
        #  apiKey = "";
        #  repositories = [
        #    "nixos/nixpkgs"
        #  ];
        #};
      };
    };
  };

  qJson = {
    wtf = {
      term = "rxvt-unicode-256color";
      colors.border = {
        focusable = "darkslateblue";
        focused = "orange";
        normal = "green";
      };
      grid = {
        columns = [ 33 12 28 36 0 ];
        rows = [ 9 3 7 6 0 ];
      };
      refreshInterval = 1;
      mods = with modules; {

        digitalclock = digitalclock {
          top = 0;
          left = 0;
        };

        clocks = clocks {
          top = 1;
          left = 0;
        };

        top = resourceusage {
          top = 0;
          left = 1;
          width = 2;
        };

        power = power {
          top = 2;
          left = 0;
        };

        rates = wtfModule {
          type = "exchangerates";
          top = 3;
          left = 0;
          title = "rates";
          rates.IDR = [ "EUR" ];
          rates.EUR = [ "IDR" ];
          refreshInterval = 3600;
        };

        weather = prettyweather {
          top = 0;
          left = 3;
        };

        calendar = cmdRunner {
          title = "";
          args = [ "-3" "--monday" "--color=never" "-w" ];
          cmd = "cal";
          top = 1;
          left = 1;
          height = 2;
          width = 3;
          refreshInterval = 3600;
        };

        active-users = cmdRunner {
          title = "users";
          cmd = activeUsers;
          top = 0;
          left = 4;
          height = 4;
          width = 1;
          refreshInterval = 30;
        };

        active-tasks = cmdRunner {
          title = "active tasks";
          cmd = activeTasks;
          top = 4;
          left = 2;
          height = 1;
          width = 3;
          refreshInterval = 60;
        };

        next-week-tasks = cmdRunner {
          title = "upcoming";
          cmd = taskNextWeek;
          top = 4;
          left = 0;
          height = 1;
          width = 2;
          refreshInterval = 60;
        };

        network-status = cmdRunner {
          title = "network status";
          cmd = networkStatus;
          top = 3;
          left = 1;
          height = 1;
          width = 3;
          refreshInterval = 60;
        };

        uptime = cmdRunner {
          enabled = false;
          title = "uptime";
          cmd = "uptime";
          top = 3;
          left = 1;
          height = 1;
          width = 3;
        };
      };
    };
  };

  createDashboard = { json, name }:
    let configuration = pkgs.writeText "config.yml" (builtins.toJSON json);
    in pkgs.writers.writeBashBin name ''
      ${unstable.wtf}/bin/wtfutil --config=${toString configuration}
    '';

in {

  services.upower.enable = true;

  environment.systemPackages = [
    unstable.wtf
    (createDashboard {
      json = qJson;
      name = "q";
    })
    (createDashboard {
      json = newsJson;
      name = "news";
    })
    #activeUsers
    #activeTasks
    pkgs.upower
  ];

}