{
  config,
  lib,
  inputs,
  ...
}:
let
  cfg = config.khscodes.infrastructure.khs-openstack-instance;
  fqdn = config.khscodes.networking.fqdn;
  provisioningUserData = config.khscodes.infrastructure.provisioning.instanceUserData;
  firewallTcpRules = lib.lists.flatten (
    lib.lists.map (p: [
      {
        direction = "ingress";
        ethertype = "IPv4";
        protocol = "tcp";
        port = p;
        remote_subnet = "0.0.0.0/0";
      }
      {
        direction = "ingress";
        ethertype = "IPv6";
        protocol = "tcp";
        port = p;
        remote_subnet = "::/0";
      }
    ]) config.networking.firewall.allowedTCPPorts
  );
  firewallUdpRules = lib.lists.flatten (
    lib.lists.map (p: [
      {
        direction = "ingress";
        ethertype = "IPv4";
        protocol = "udp";
        port = p;
        remote_subnet = "0.0.0.0/0";
      }
      {
        direction = "ingress";
        ethertype = "IPv6";
        protocol = "udp";
        port = p;
        remote_subnet = "::/0";
      }
    ]) config.networking.firewall.allowedUDPPorts
  );
  firewallIcmpRules = lib.lists.optionals config.networking.firewall.allowPing [
    {
      direction = "ingress";
      ethertype = "IPv4";
      protocol = "icmp";
      remote_subnet = "0.0.0.0/0";
    }
    {
      direction = "ingress";
      ethertype = "IPv6";
      protocol = "icmp";
      remote_subnet = "::/0";
    }
  ];
  firewallRules = firewallTcpRules ++ firewallUdpRules ++ firewallIcmpRules ++ cfg.extraFirewallRules;
  tldFromFqdn =
    fqdn:
    let
      split = lib.strings.splitString "." fqdn;
    in
    if lib.lists.length split < 3 then
      fqdn
    else
      lib.strings.removePrefix "${builtins.head split}." fqdn;
in
{
  options.khscodes.infrastructure.khs-openstack-instance = {
    enable = lib.mkEnableOption "enables generating a opentofu config for khs openstack instance";
    dnsNames = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      description = "DNS names for the instance";
      default = [ fqdn ];
    };
    bucket = {
      key = lib.mkOption {
        type = lib.types.str;
        description = "Key for use in the bucket";
        default = "${fqdn}.tfstate";
      };
    };
    flavor = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      description = "The server type to create";
      default = null;
    };
    ssh_key = lib.mkOption {
      type = lib.types.str;
      description = "SSH key for the server (this only applies to the initial creation, deploying NixOS will render this key useless). Changing this will recreate the instance";
      default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqY0FHnWFKfLG2yfgr4qka5sR9CK+EMAhzlHUkaQyWHTKD+G0/vC/fNPyL1VV3Dxc/ajxGuPzVE+mBMoyxazL3EtuCDOVvHJ5CR+MUSEckg/DDwcGHqy6rC8BvVVpTAVL04ByQdwFnpE1qNSBaQLkxaFVdtriGKkgMkc7+UNeYX/bv7yn+APqfP1a3xr6wdkSSdO8x4N2jsSygOIMx10hLyCV4Ueu7Kp8Ww4rGY8j5o7lKJhbgfItBfSOuQHdppHVF/GKYRhdnK6Y2fZVYbhq4KipUtclbZ6O/VYd8/sOO98+LMm7cOX+K35PQjUpYgcoNy5+Sw3CNS/NHn4JvOtTaUEYP7fK6c9LhMULOO3T7Cm6TMdiFjUKHkyG+s2Mu/LXJJoilw571zwuh6chkeitW8+Ht7k0aPV96kNEvTdoXwLhBifVEaChlAsLAzSUjUq+YYCiXVk0VIXCZQWKj8LoVNTmaqDksWwbcT64fw/FpVC0N18WHbKcFUEIW/O4spJMa30CQwf9FeqpoWoaF1oRClCSDPvX0AauCu0JcmRinz1/JmlXljnXWbSfm20/V+WyvktlI0wTD0cdpNuSasT9vS77YfJ8nutcWWZKSkCj4R4uHeCNpDTX5YXzapy7FxpM9ANCXLIvoGX7Yafba2Po+er7SSsUIY1AsnBBr8ZoDVw==";
    };
    extraFirewallRules = lib.mkOption {
      type = lib.types.listOf lib.types.attrs;
      description = "Extra firewall rules added to the instance";
      default = [
        {
          direction = "egress";
          ethertype = "IPv4";
          protocol = "tcp";
          port = 80;
          remote_subnet = "0.0.0.0/0";
        }
        {
          direction = "egress";
          ethertype = "IPv6";
          protocol = "tcp";
          port = 80;
          remote_subnet = "::/0";
        }
        {
          direction = "egress";
          ethertype = "IPv4";
          protocol = "tcp";
          port = 443;
          remote_subnet = "0.0.0.0/0";
        }
        {
          direction = "egress";
          ethertype = "IPv6";
          protocol = "tcp";
          port = 443;
          remote_subnet = "::/0";
        }
        {
          direction = "egress";
          ethertype = "IPv4";
          protocol = "udp";
          port = 443;
          remote_subnet = "0.0.0.0/0";
        }
        {
          direction = "egress";
          ethertype = "IPv6";
          protocol = "udp";
          port = 443;
          remote_subnet = "::/0";
        }
        {
          direction = "egress";
          ethertype = "IPv4";
          protocol = "icmp";
          remote_subnet = "0.0.0.0/0";
        }
        {
          direction = "egress";
          ethertype = "IPv6";
          protocol = "icmp";
          remote_subnet = "::/0";
        }
      ];
    };
  };
  config = lib.mkIf cfg.enable (
    let
      tags = [ fqdn ];
      modules = [
        (
          { config, ... }:
          {
            imports = [
              inputs.self.terranixModules.cloudflare
              inputs.self.terranixModules.openstack
              inputs.self.terranixModules.unifi
              inputs.self.terranixModules.s3
            ];
            config = {
              khscodes.s3 = {
                enable = true;
                bucket.key = cfg.bucket.key;
              };
              khscodes.openstack.enable = true;
              khscodes.openstack.compute_instance.compute = {
                inherit tags;
                name = fqdn;
                initial_image = "debian-12";
                flavor = cfg.flavor;
                ssh_public_key = cfg.ssh_key;
                firewall_rules = firewallRules;
                user_data = provisioningUserData;
              };
              khscodes.unifi.enable = true;
              khscodes.unifi.static_route.compute = {
                name = fqdn;
                network = config.khscodes.openstack.output.compute_instance.compute.ipv6_cidr;
                distance = 1;
                next_hop = config.khscodes.openstack.output.compute_instance.compute.ipv6_external_gateway;
              };
              khscodes.cloudflare = {
                enable = true;
                dns = {
                  enable = true;
                  zone_name = tldFromFqdn fqdn;
                  aRecords = [
                    {
                      inherit fqdn;
                      content = config.khscodes.openstack.output.compute_instance.compute.ipv4_address;
                    }
                  ];
                  aaaaRecords = [
                    {
                      inherit fqdn;
                      content = config.khscodes.openstack.output.compute_instance.compute.ipv6_address;
                    }
                  ];
                };
              };
              output.ipv4_address = {
                value = config.khscodes.openstack.output.compute_instance.compute.ipv4_address;
                sensitive = false;
              };

              output.ipv6_address = {
                value = config.khscodes.openstack.output.compute_instance.compute.ipv6_address;
                sensitive = false;
              };
            };
          }
        )
      ];
    in
    {
      assertions = [
        {
          assertion = config.khscodes.networking.fqdn != null;
          message = "Must set config.khscodes.networking.fqdn when using opentofu";
        }
      ];
      khscodes.services.openssh = {
        enable = true;
        hostCertificate = {
          enable = true;
        };
      };
      khscodes.infrastructure.provisioning = {
        pre = {
          modules = modules;
          endpoints = [
            "aws"
            "cloudflare"
            "openstack"
            "unifi"
          ];
        };
        preImageUsername = "debian";
      };
    }
  );
}
