{ inputs, khscodesLib }:
{ config, lib, ... }:
let
  cfg = config.khscodes.hcloud;
  serversWithRdns = lib.filterAttrs (_: value: value.rdns != null) cfg.server;
  mapSanitizedAttrs =
    f: list:
    lib.listToAttrs (
      lib.map (
        { name, value }:
        let
          sanitizedName = khscodesLib.sanitize-terraform-name name;
        in
        {
          name = sanitizedName;
          value = f {
            inherit value;
            name = sanitizedName;
          };
        }
      ) (lib.attrsToList list)
    );
  hcloudServerModule = khscodesLib.mkSubmodule {
    description = "Module for defining hcloud server";
    options = {
      name = lib.mkOption {
        type = lib.types.str;
        description = "Name of the server";
      };
      server_type = lib.mkOption {
        type = lib.types.str;
        description = "Server type for the instance";
      };
      datacenter = lib.mkOption {
        type = lib.types.str;
        description = "Data center for the instance";
      };
      initial_image = lib.mkOption {
        type = lib.types.str;
        description = "Initial image of the server";
      };
      ssh_keys = lib.mkOption {
        type = lib.types.listOf lib.types.str;
        description = "The ssh keys added to the server";
      };
      labels = lib.mkOption {
        type = lib.types.attrsOf lib.types.str;
      };
      rdns = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "FQDN to map rDNS to";
      };
      user_data = lib.mkOption {
        type = lib.types.str;
        default = "";
        description = "User data for the instance";
      };
    };
  };
  hcloudDataSshKeys = khscodesLib.mkSubmodule {
    description = "SSH Keys";
    options = {
      name = lib.mkOption {
        type = lib.types.str;
        description = "The name of the ssh keys";
      };
      id = lib.mkOption {
        type = lib.types.str;
        description = "A terraform expression for the ssh keys";
      };
    };
  };
in
{
  options.khscodes.hcloud = {
    enable = lib.mkEnableOption "Enables khscodes hcloud terranix integration";
    server = lib.mkOption {
      type = lib.types.attrsOf hcloudServerModule;
      description = "Defines an hcloud server";
      default = { };
    };
    data.ssh_key = lib.mkOption {
      type = lib.types.attrsOf hcloudDataSshKeys;
      description = "Reads ssh keys as data source from hcloud";
      default = { };
    };
  };
  imports = [
    inputs.terranix-hcloud.terranixModules.hcloud
    (import ./output.nix { inherit inputs khscodesLib; })
  ];
  config = lib.mkIf cfg.enable {

    hcloud.enable = true;
    terraform.required_providers.hcloud.version = "~> 1.51.0";
    resource.hcloud_server = mapSanitizedAttrs (
      { name, value }:
      {
        inherit (value)
          server_type
          datacenter
          labels
          ssh_keys
          name
          ;
        image = value.initial_image;
        public_net = {
          ipv4_enabled = true;
          ipv4 = "\${ hcloud_primary_ip.${name}_ipv4.id }";
          ipv6_enabled = true;
          ipv6 = "\${ hcloud_primary_ip.${name}_ipv6.id }";
        };
        user_data = builtins.toJSON value.user_data;
        lifecycle = {
          ignore_changes = [
            "ssh_keys"
            "public_net"
            "image"
          ];
        };
      }
    ) cfg.server;
    resource.hcloud_primary_ip =
      (lib.mapAttrs' (
        name: value:
        let
          sanitizedName = khscodesLib.sanitize-terraform-name name;
        in
        {
          name = "${sanitizedName}_ipv4";
          value = {
            inherit (value) labels;
            name = "${value.name} ipv4";
            datacenter = value.datacenter;
            type = "ipv4";
            assignee_type = "server";
            auto_delete = false;
          };
        }
      ) cfg.server)
      // (lib.mapAttrs' (
        name: value:
        let
          sanitizedName = khscodesLib.sanitize-terraform-name name;
        in
        {
          name = "${sanitizedName}_ipv6";
          value = {
            inherit (value) labels;
            name = "${value.name} ipv6";
            datacenter = value.datacenter;
            type = "ipv6";
            assignee_type = "server";
            auto_delete = false;
          };
        }
      ) cfg.server);
    resource.hcloud_rdns =
      (lib.mapAttrs' (
        name: value:
        let
          sanitizedName = khscodesLib.sanitize-terraform-name name;
        in
        {
          name = "${sanitizedName}_ipv4";
          value = {
            primary_ip_id = "\${ hcloud_primary_ip.${sanitizedName}_ipv4.id }";
            ip_address = "\${ hcloud_server.${sanitizedName}.ipv4_address }";
            dns_ptr = value.rdns;
          };
        }
      ) serversWithRdns)
      // (lib.mapAttrs' (
        name: value:
        let
          sanitizedName = khscodesLib.sanitize-terraform-name name;
        in
        {
          name = "${sanitizedName}_ipv6";
          value = {
            primary_ip_id = "\${ hcloud_primary_ip.${sanitizedName}_ipv6.id }";
            ip_address = "\${ hcloud_server.${sanitizedName}.ipv6_address }";
            dns_ptr = value.rdns;
          };
        }
      ) serversWithRdns);
    data.hcloud_ssh_key = mapSanitizedAttrs (
      { value, ... }:
      {
        name = value.name;
      }
    ) cfg.data.ssh_key;
  };
}
