#!/usr/bin/perl -w

use utf8;
use strict;
use warnings;

BEGIN {
    unshift @INC, ( $ENV{POPHOME} || '@POPHOME@' ) . '/lib'
      unless $ENV{KUNDE_NO_PERLPATH};
}

use Cf qw($NS_EXT $UPDATE_ZONEN_COMMAND);
use Dbase::Globals
  qw(def_or_minus find_descr flag_names get_ipkunde get_gruppen);
use Dbase::Help qw(Do DoFn DoTime DoTrans qquote);
use Loader qw(log_update);
use noris::REST::Backend qw(get_param error success);

my $mask_domainflags_dnszone = get_gruppen( domainflags => dnszone => 1 );
my %noris_dns = map +( lc() => undef ), split ' ', $NS_EXT;

my $dns_master = get_param( ipaddress => 'dns_master' );
my $domain     = get_param( hostname  => 'domain' );
my $reseller   = get_param( printable => 'reseller' );

my $flags_soll = 0;
{
    require Net::DNS;

    my $resolver =
      Net::DNS::Resolver->new( nameservers => [$dns_master], retrans => 1 )
      or error(
'Es ist ein interner Fehler bei der Erzeugung eines Resolver-Objekts aufgetreten.'
      );

    my $answer = $resolver->send( $domain, 'NS' )
      or error(
'Es ist ein interner Fehler bei der DNS-Abfrage des Masters aufgetreten: '
          . $resolver->errorstring );

    error(
"Auf dem Server $dns_master ist keine entsprechende DNS-Zone aufgesetzt."
    ) unless $answer->header->aa;

    my @nserver = $answer->answer
      or error('Der Master liefert keine NS-Records fuer den Domainnamen.');

    for (@nserver) {
        next unless exists $noris_dns{ lc $_->nsdname };
        $flags_soll |= $mask_domainflags_dnszone;
        last;
    }
}

DoTrans {

    my $ipkunde_id = get_ipkunde( $dns_master, 2 )
      or error(qq(DNS-Server "$dns_master" ist nicht registriert.));

    $reseller =~ /([^.]*)\z/;    # Sub-Reseller, vgl. RT#406317-10
    my ( $kunde_id, $mail_ip ) =
      DoFn( 'SELECT id, mail_ip FROM kunde WHERE name = ' . qquote($1) );
    $kunde_id = DoFn( "SELECT kunde FROM uucpkunde WHERE name = " . qquote($1) )
      or error(qq(Es gibt keinen Reseller "$reseller".))
      unless defined $kunde_id;

    my $qdomain = qquote($domain);
    my $now     = DoTime();

    {
        my $domainstatus_geloescht =
          find_descr( domainstatus => geloescht => 1 );

        Do(<<_);    # s. RT#459102-4
	UPDATE domainkunde SET ende = $now
	WHERE  domain = $qdomain
	   AND ende   > $now
	   AND status = $domainstatus_geloescht
_
    }

    unless ( my ( $id, $domain_kunde, $nserver, $flags, $ende ) = DoFn(<<_) ) {
	SELECT id, kunde, nserver, flags, ende
	FROM   domainkunde
	WHERE  domain = $qdomain AND ( ende IS NULL OR ende > $now )
	FOR UPDATE
_

        my $domainstatus_beantragt =
          find_descr( domainstatus => beantragt => 1 );
        my $nic_partnergate = find_descr( nic => partnergate => 1 );

        my $domain_id = Do(<<_);
	INSERT INTO domainkunde SET
		beginn   = $now,
		domain   = $qdomain,
		kunde    = $kunde_id,
		mail_ip  = ${\ qquote($mail_ip) },
		nic      = $nic_partnergate,
		nserver  = $ipkunde_id,
		flags    = $flags_soll,
		status   = $domainstatus_beantragt
_
        log_update(
            domainkunde =>
              id => $domain_id,
            undef,
            domain => '*',
            undef, $domain
        );
    }
    elsif ( $domain_kunde != $kunde_id ) {
        error(qq(Die Domain "$domain" gehört einem anderen Kunden.));
    }
    elsif ($ende) {

        # Bislang ist kein einschlägiger Fall bekannt.
	# Sollte er doch mal auftreten, behandeln wir das erstmal als Fehler,
	# da unklar ist, was ggf. sinnvoll getan werden sollte,
	# insbesondere hinsichtlich des zugehörigen Kundentarifs.
        error(
            qq(Die Domain "$domain" ist bekannt, wird aber demnächst beendet.)
        );
    }
    elsif (
        ( my $flags_ok = ( $flags & $flags_soll ) == $flags_soll )
        && ( my $has_correct_nserver =
            defined $nserver && $nserver == $ipkunde_id )
      )
    {
        success(
            $flags_soll & $mask_domainflags_dnszone
            ? qq(Für die Domain "$domain" ist bereits eine Slave-DNS-Zone mit "$dns_master" als Master-DNS-Server registriert.)
            : qq(Die Domain "$domain" ist bereits mit "$dns_master" als Master-DNS-Server registriert; eine Slave-Zone ist nicht erforderlich.)
        );
    }
    else {
        my @update;
        unless ($flags_ok) {
            my $new_flags = $flags | $flags_soll;
            log_update(
                domainkunde =>
                  id => $id,
                undef,
                flags => undef,
                scalar flag_names( $new_flags, domainflags => $flags )
            );
            push @update, "flags=$new_flags";
        }
        unless ($has_correct_nserver) {
            log_update(
                domainkunde =>
                  id => $id,
                undef,
                nserver => undef,
                def_or_minus($nserver)
            );
            push @update, "nserver=$ipkunde_id";
        }

        Do(     'UPDATE domainkunde SET '
              . join( ', ', @update )
              . " WHERE id = $id" );
    }
};

success('Die Domain wurde erfolgreich in unserer Datenbank angelegt.')
  unless $flags_soll & $mask_domainflags_dnszone;

system $UPDATE_ZONEN_COMMAND
  and error('Fehler bei der Aktualisierung der Zonenliste.');

success('Die DNS-Zone wurde erfolgreich eingerichtet.');
