set -euo pipefail

. driglibash-base

fakeresolve_ip_list () {
	if [ "$#" -ne 1 ] ; then
		die "Usage: fakeresolve_ip_list <name>"
	fi
	grep -oP "^$1[[:space:]]+(IN)?[[:space:]]+A{1,4}[[:space:]]+\K[^;\s]+" "$debian_bind_confdir/$server_zone_file" | tr '\n' ';'
}

prepare () {
	# Install dependencies
	apt install -y bind9 &>/dev/null
	
	# Create Directories
	if [ -n "$keydir" ] ; then
		mkdir -p "$keydir"
		chown bind:bind "$keydir" -R
		chown bind:bind "$debian_bind_confdir" -R
	fi
	
	echo 'Sync the git repo'
	run sudo -u bind git_update.sh -N -b main -i "$DATA_DIR/gitkey" -d "$debian_bind_confdir" 'ssh://git@git.jean-cloud.net:22529/adrian/dnszones.git'
	cd /etc/bind
	
	
	echo 'Prepare bind: Remove autogenerated part from bind conf files'
	rm /etc/bind/*.jnl &>/dev/null || true
	sed -i -n "/$autoconf_separator/q;p" "$debian_bind_confdir"/*
	
	echo 'Put the separator back'
	for file in $( ls "$debian_bind_confdir"/template.db.* | grep -v '.signed$\|.jbk$\|.jnl$') ; do
		echo "$autoconf_separator" >> "$file"
	done

}

restart () {
	echo 'Check named conf'
	run named-checkconf "$debian_bind_confdir/named.conf"
	for db_file in $(list_db_files) ; do
		domain="$(basename "$db_file")"
		domain="${domain:3}"
		run named-checkzone "$domain" "$db_file"
	done

	echo 'Restart named'
	systemctl restart named
}

# Function that simulate a DNS resolve by reading bind zone file
# Returns all the record line:
# @ IN A X.X.X.X
fakeresolve () {
	if [ "$#" -ne 1 ] ; then
		die "Usage: fakeresolve <name>"
	fi
	name="$1"
	
	zonefile="$debian_bind_confdir/$server_zone_file"

	# Split full name if there are dots
	shortname="$name"
	if [ -n "$(echo "$name" | grep -o '\.')" ] ; then
		shortname="$(echo "$name" | grep -Po '^.*(?=\.[^\.]+\.[^\.]+$)' || true)"
	fi

	grep -v -e  '^[[:space:]]*;' "$zonefile"  |grep -oP "^[[:space:]]*$shortname\K[[:space:]]*(IN)?[[:space:]]*A{1,4}[[:space:]]*[\S;]+" | sed 's/^/@/'

}

# Function that add DNS record in the right file
addbindline () {
	if [ "$#" -ne 2 ] ; then
		die "Usage: addbindline <name> <target_cname>"
	fi

	name="$1"
	target="$2"

	# extract the truc.com part
	domain="$(echo "$name" | grep -o '[^\.]\+\.[^\.]\+$' || true)"	
	[ -z "$domain" ] && return 0

	# extract the subdomain part (www)
	shortname="$(echo "$name" | grep -Po '^.*(?=\.[^\.]+\.[^\.]+$)' || true)"

	# bind DB file
	bindfile="$debian_bind_confdir/db.$domain"

	# Only append if db file exists
	[ ! -f "$bindfile" ] && return 0

	# BTW allow ACME DNS update
	token="#JC-ACME $domain"
	acme_dns="grant letsencrypt.key. name _acme-challenge.$name. TXT;"
	sed -i "s/\([[:space:]]*\)$token/\1$acme_dns\n\1$token/" "$debian_bind_confdir/named.conf.local"


	# TODO check if name already existst with a different target
	# Hard since we are resolving targets now…

	# CNAME are forbiden for empty shortnames, so we must resolve the target IPs
	# For performance reasons, we just put plain IP everywhere
	# to put aliases in place of ip juste do the following if $shortname is empty:
	#line_in_file "$shortname CNAME $target." "$bindfile"
	while read line ; do
		if [ -n "$shortname" ] ; then
			line="$(echo "$line" | sed "s/@/$shortname/")"
		fi
		line_in_file "$line" "$bindfile"
	done < <(fakeresolve "$target")
}

list_template_db_files () {
	ls "$debian_bind_confdir"/template.db.*
}

list_db_files () {
	ls "$debian_bind_confdir"/db.* | grep -v -e '.jbk$' -e '.signed$' -e '.signed.jnl'
}


create_primary_files () {
	# Compact the default SOA
	SOA="$(grep -o '^[^;]*' SOA | sed -z -e 's/[[:space:]]\{2,\}/ /g' -e 's/\n/\\n/')"
	
	line_in_file "include \"$DATA_DIR/letsencrypt.key\";" "$debian_bind_confdir/named.conf"
	
	for file in $(list_template_db_files) ; do
		domain="$(basename "$file" | sed 's/template.db.//')"
		new_db_file="$(echo "$file" | sed 's/template.db./db./')"

		# Set the default SOA if needed
		sed "s/^;JC_AUTOSOA$/$SOA/" "$file" > "$new_db_file"

		# Set serial
		serial="$(date '+%s')"
		sed -i "s/\(@ SOA [^(]*( \)[0-9]\+/\1$serial/"  "$new_db_file"

		# Add this dns server if not present
		if ! grep -q '[^;].*(IN)?.*NS.*' "$new_db_file" ; then
			cat default_ns >> "$new_db_file"
		fi

		# Add DS record
		#if [ -n "$(ls "$DATA_DIR/keys/K$domain"*.key)" ] ; then
			#dnssec-dsfromkey "$DATA_DIR/keys/K$domain"*.key | sed "s/${domain}./@/" >> "$new_db_file"
		#fi

		# Populate named.conf.local
		cat  >> "$debian_bind_confdir/named.conf.local" <<-EOF
			zone "$domain" {
				# Zone file
			    type master;
			    file "$new_db_file";

				# Secondary conf
			    # https://kb.isc.org/docs/aa-00723
			    #allow-update { !{!{$secondary_ips};any;}; key update-key; };
			    allow-transfer { $secondary_ips };
			    also-notify { $secondary_ips };
			    notify yes;

				# DNSSEC
			    dnssec-policy default;
			    inline-signing yes;
			    key-directory "$DATA_DIR/keys";

				# ACME autorizations
		        update-policy {    
		    	    #JC-ACME $domain  
		    	};    

			};
		EOF

	
	done
	
	echo 'Find every used domain and add them to bind db'
	while IFS=';' read -r id username service target
	do
		addbindline "$service" "$target"
		nginxfile="/docker/$service/nginx_server.conf"
		if [ -f "$nginxfile" ] ; then
			for name in $(extract_domain_nginx_conf.sh "$nginxfile" | template.sh "/docker/$service/.env") ; do
				addbindline "$name" "$target"
			done
		fi
	done < <(grep -v '^#' /docker/services.csv)
}

create_secondary_files () {
	primary_ips="$(echo "$primary_ips" | sed 's/^;//')"
	for file in "$debian_bind_confdir"/template.db.* ; do
		file="$(echo "$file" | sed -e 's/template.db.//' -e "s#$debian_bind_confdir#/var/lib/bind/#")"
		domain="$(basename "$file")"
	
		echo -n "
zone \"$domain\" {
	masters { $primary_ips };
    type slave;
    file \"$file\";
};" >> "$debian_bind_confdir/named.conf.local"
	done
}
