{ inputs, khscodesLib }:
{ config, lib, ... }:
let
  cfg = config.khscodes.cloudflare;
  nameFromFQDNAndZone =
    fqdn: zone:
    let
      stripped = lib.strings.removeSuffix ".${zone}" fqdn;
    in
    if stripped != fqdn then
      stripped
    else if fqdn == zone then
      "@"
    else
      fqdn;
  dnsARecordModule = khscodesLib.mkSubmodule {
    description = "Module for defining dns A/AAAA record";
    options = {
      fqdn = lib.mkOption {
        type = lib.types.str;
        description = "The FQDN of the A/AAAA record to create";
      };
      content = lib.mkOption {
        type = lib.types.str;
        description = "The content of the A/AAAA record (IPv4/IPv6 address)";
      };
      proxied = lib.mkOption {
        type = lib.types.bool;
        description = "Creates a proxied record in cloudflare";
        default = false;
      };
      ttl = lib.mkOption {
        type = lib.types.int;
        description = "Time to Live for the A/AAAA record";
        default = 600;
      };
    };
  };
  dnsTxtRecordModule = khscodesLib.mkSubmodule {
    description = "Module for defining dns TXT record";
    options = {
      fqdn = lib.mkOption {
        type = lib.types.str;
        description = "The FQDN of the TXT record to create";
      };
      content = lib.mkOption {
        type = lib.types.str;
        description = "The content of the TXT record";
      };
      ttl = lib.mkOption {
        type = lib.types.int;
        description = "Time to Live for the TXT record";
        default = 600;
      };
    };
  };
  dnsMxRecordModule = khscodesLib.mkSubmodule {
    description = "Module for defining dns MX record";
    options = {
      fqdn = lib.mkOption {
        type = lib.types.str;
        description = "The FQDN of the MX record to create";
      };
      content = lib.mkOption {
        type = lib.types.str;
        description = "The content of the MX record";
      };
      priority = lib.mkOption {
        type = lib.types.int;
        description = "Priority for the MX record";
      };
      ttl = lib.mkOption {
        type = lib.types.int;
        description = "Time to Live for the MX record";
        default = 600;
      };
    };
  };
in
{
  options.khscodes.cloudflare = {
    enable = lib.mkEnableOption "Enables khscodes cloudflare terranix integration";
    dns = {
      enable = lib.mkEnableOption "Enables setting up DNS records";
      zone_name = lib.mkOption {
        type = lib.types.str;
        description = "The dns zone name (TLD)";
      };
      aRecords = lib.mkOption {
        type = lib.types.listOf dnsARecordModule;
        default = [ ];
        description = "A records to create in the zone";
      };
      aaaaRecords = lib.mkOption {
        type = lib.types.listOf dnsARecordModule;
        default = [ ];
        description = "AAAA records to create in the zone";
      };
      txtRecords = lib.mkOption {
        type = lib.types.listOf dnsTxtRecordModule;
        default = [ ];
        description = "TXT Records to create";
      };
      mxRecords = lib.mkOption {
        type = lib.types.listOf dnsMxRecordModule;
        default = [ ];
        description = "MX records to create";
      };
    };
  };

  config = lib.mkIf cfg.enable {
    provider.cloudflare.api_token = "\${ var.cloudflare_token }";
    variable.cloudflare_token = {
      type = "string";
      sensitive = true;
    };
    terraform.required_providers.cloudflare = {
      source = "cloudflare/cloudflare";
      version = "~> 4.0";
    };

    data.cloudflare_zone.dns_zone = lib.attrsets.optionalAttrs cfg.dns.enable {
      name = cfg.dns.zone_name;
    };
    resource.cloudflare_record = lib.attrsets.optionalAttrs cfg.dns.enable (
      lib.listToAttrs (
        (lib.lists.map (record: {
          name = "${khscodesLib.sanitize-terraform-name record.fqdn}_a";
          value = {
            inherit (record) content ttl proxied;
            name = nameFromFQDNAndZone record.fqdn cfg.dns.zone_name;
            type = "A";
            zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
            comment = "app=${cfg.dns.zone_name}";
          };
        }) cfg.dns.aRecords)
        ++ (lib.lists.map (record: {
          name = "${khscodesLib.sanitize-terraform-name record.fqdn}_aaaa";
          value = {
            inherit (record) content ttl proxied;
            name = nameFromFQDNAndZone record.fqdn cfg.dns.zone_name;
            type = "AAAA";
            zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
            comment = "app=${cfg.dns.zone_name}";
          };
        }) cfg.dns.aaaaRecords)
        ++ (lib.lists.map (record: {
          name = "${khscodesLib.sanitize-terraform-name record.fqdn}_txt";
          value = {
            inherit (record) content ttl;
            name = nameFromFQDNAndZone record.fqdn cfg.dns.zone_name;
            type = "TXT";
            zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
            comment = "app=${cfg.dns.zone_name}";
          };
        }) cfg.dns.txtRecords)
        ++ (lib.lists.map (record: {
          name = "${khscodesLib.sanitize-terraform-name record.fqdn}_mx";
          value = {
            inherit (record) content priority;
            name = nameFromFQDNAndZone record.fqdn cfg.dns.zone_name;
            type = "MX";
            zone_id = "\${ data.cloudflare_zone.dns_zone.id }";
            comment = "app=${cfg.dns.zone_name}";
          };
        }) cfg.dns.mxRecords)
      )
    );
  };
}
