#!/usr/bin/perl
#========================================================================
#
# mk_site: script to facilitate the creation of new RPS sites.
#   It doesn't actually create the site, but instead outputs
#   an itemized list of the things you need to modify in order
#   to have the site created:
#
#   * Setup a DNS entry for the new site.
#   * common/lib/Common/RSDB.pm
#   * common/lib/Common/Consts.pm
#   * data_classes/lib/Client/Client.pm
#   * dbadmin/bin/create_sites_production.sh
#   * dbadmin/bin/create_sites_staging.sh
#   * common/production/images/logos/${vhost}.gif
#
#   You'll also need to get a DNS entry created for the new site.
#
# You will be asked for the following information:
#
# - The name of the client.  This should be regular ASCII.
#
# - The vhost name.  A virtual host will be setup on one of two web
#   servers (determined when you input the server info, below).
#
# - The 2-character country code to associate with the client
#   (this information will also be used to derive the currency
#    code for the client).
#
# - The default payor name.
#
# - The type of client.  All clients have 'Digital Advantage' enabled;
#   you will need to select any additional service(s) for the client.
#
# - The server that the client will be hosted on (rps01 or rps02).
#   This will be used to determine which database host the client's
#   data will reside on, as well as the web server that will host
#   the client's website.
#
#========================================================================
use strict;

$| = 1;

use Sys::Hostname;
use Getopt::Std;
use Data::Dumper;
use YAML::Syck;
use POSIX;

use lib '/app/tools/common/lib';
use Common::RSDB;
use Common::Consts;
use Common::RSApp;
use Common::CurrencyFormat;

my %opt;
getopts('h:un:y:', \%opt);

die usage() if $opt{t};

my $CMD = 'mysql -uroot';

my $startID = $opt{n};
my $serverID = $opt{h} || 'rpsweb03';

#--------------------------------------------------------------
# Build up a hash of client data (this used to be in Consts.pm,
# but was removed as part of FB14274).
#--------------------------------------------------------------
my %CLIENT_NAME_CLEAN;
my %gTypeMask;

my $appSingleton = Common::RSApp->new( clientID => 0 );
my $cdbo = Common::RSApp::GetCommonDB();

my $sql = "SELECT client_id, client_name_clean, type_mask FROM client";
my $sth = $cdbo->DoCmd($sql); # RSCOMMON

while( my( $clientID, $clientNameClean, $typeMask ) = $sth->fetchrow_array() )
{
   $CLIENT_NAME_CLEAN{$clientID}  = $clientNameClean;
   $gTypeMask{$clientID}  = $typeMask;
}


#===============================================
# 1) Find the highest client_id currently in use
#===============================================

my $numClients = scalar(keys %Common::RSDB::CLIENT_DB);
my $clientID;
foreach my $id(sort{ $a <=> $b } keys %Common::RSDB::CLIENT_DB  )
{

   # Skip the special IDs
   #
   next if( ($id =~ /\d\d{9}/) || $id =~ /^(777|998|999)$/ );

   my $name = $CLIENT_NAME_CLEAN{$id};
   $clientID = $id + 1;
}

my $newClientID = $startID || $clientID;

my @clientList;

if ( $opt{y} ) {
    my ( $clients, $startingClientID ) = clients( $opt{y} );   
    print "clients = ". Dumper(@$clients) . "\n";
    print "starting client_id = $startingClientID\n";
    $newClientID = $startingClientID if ( $startingClientID );

    foreach my $e ( @$clients ) {

        my $orchardSync = (exists $e->{orchard_sync} && $e->{orchard_sync} =~ /^y/i) ? 1 : 0;
        my $jira        = (exists $e->{jira}) ? $e->{jira} : 'RSD-XXX';

        print "name:         ". $e->{name} . "\n";
        print "jira:         ". $jira . "\n";
        print "module:       ". $e->{'royalty module'} . "\n";
        print "url:          ". $e->{url} . "\n";
        print "label:        ". $e->{label} . "\n";
        print "payor:        ". $e->{payor} . "\n";
        print "currency:     ". $e->{currency} . "\n";
        print "orchard_sync: ". $orchardSync . "\n";
        print "\n";

        # transform items from config file
        my $url = $e->{url};
        my $vhost = lc $url;
        $vhost =~ s/\.royaltyshare\.com//;

        my $dbName = getClientDBName($vhost);

        my $codeName = $e->{name};
        $codeName =~ s/ //g;
        $codeName =~ s/,//g;
        $codeName =~ s/\.//g;
        $codeName =~ s/://g;

        my $defaultPayor = $e->{payor};
        $defaultPayor =~ s/ /\\ /g;
        $defaultPayor =~ s/&/\\&/g;
        print "defaultPayor: $defaultPayor\n";

        my $defaultLabel = $e->{label};
        $defaultLabel =~ s/ /\\ /g;
        $defaultLabel =~ s/&/\\&/g;
        print "defaultLabel $defaultLabel\n";

        my $serverID = $e->{server} || 'rps03';
        my($dbHost, $webHost) = getHosts($serverID);
        $dbHost = 'db01'; # override the legacy db assignments

        my $module = $e->{'royalty module'};
        my $typeMask = getClientMask($module);

        my $clientName = $e->{name};
        $clientName =~ s/ /\\ /g;
        $clientName =~ s/:/\\:/g;

        my $countryCode = $e->{country_code};
        my $cf = new Common::CurrencyFormat( countryCode => $countryCode );
        my $currencyCode = $cf->currencyCode();

        push @clientList, {
            id       => $newClientID++,
            name     => $e->{name},
            jira     => $jira,
            clientName => $clientName,
            vhost    => $vhost,
            dbName   => $dbName,
            typeMask => $typeMask,
            codeName => $codeName,
            defaultPayor => $defaultPayor,
            defaultLabel => $defaultLabel,
            serverID => $serverID,
            dbHost   => $dbHost,
            webHost  => $webHost,
            module   => $e->{'royalty module'},
            url      => $e->{url},
            label    => $e->{label},
            payor    => $e->{payor},
            countryCode  => $countryCode,
            currencyCode => $currencyCode,
            orchardSync  => $orchardSync,
        };
    }

}

createClient( \@clientList );

die("done!");


sub createClient {
    #my ( %args ) = @_;
    my $args = shift;

    print "\n######## 8< ---- cut here ----- >8 ########\n";

    outputCommonRSDBStaticListYml( $args );

    print "\n";

    outputCommonConsts( $args );

    print "\n";

    outputClientClient( $args );

    print "\n";

    outputCommonClient( $args );

    print "\n";

    outputCreateSitesProduction( $args );

    print "\n";

    outputCreateSitesStaging( $args );

    return;


} # createClient

#/////////////////////////////////////////////////

# This method will enable the Orchard Sync option  if the orchard_sync option is specified for
# any client in the yml file.. We need to update a perl module _and_ add a dummy entry to the
# database..
sub outputCommonClient {
    my $args = shift;

    my $_clientID = $args->[0]{id};
    my $file = "/app/tools/common/lib/Common/Client.pm";
    #my $pc = $_clientID - 1;
    #print "\n  * Added entry to config file\n\n";
    #print "$pc:\n";
    #print "  . . .\n";

    my @clients;
    my $jira; # case number to use when generating SQL update script
    foreach my $c ( @$args ) {
        my $clientID    = $c->{id};
        my $dbName      = $c->{dbName};
        my $dbHost      = $c->{dbHost};
        my $webHost     = $c->{webHost};
        my $orchardSync = $c->{orchardSync};
        $jira           = $c->{jira} if ( !$jira );  # remember the first ticket

        if ( $orchardSync ) {
            push @clients, $clientID;
        }
    }

    if ( @clients > 0 ) {
        _printHeader("Here are the changes for common/lib/Common/Client.pm");

        # Print out the block of lines containing the orchardClients array.  We'l
        # print a line showing the approximate location to add the new client id
        # NB: we use 'nl' to add in line numbers
        #
        my $res = `nl -ba $file | sed -n '/my \@orchardClients/,/test sites/p'`;
        my @lines = split('\n',$res);

        foreach my $line (@lines) {

            if ( $line =~ /test sites/ ) {

                print "                ". join(', ', @clients) . ",  # <--- NEW CLIENT_ID(S)\n";
            }
            print "$line\n";

        }

        # Generate orchard_client update script.
        # Note: the filename must compatible with db_deploy
        # Example:  2023 2022-06-21_01-01_UTC_RSD-7928_mfa_update_esongalia.sql

        my @clientList = map { "($_,1)" } @clients;

        my $whoami = `whoami`;
        chomp $whoami;
        my $base      = "/app/tools/common/sql/script/RSCOMMON";
        my $timestamp = strftime "%Y-%m-%d_%H-%M_UTC", gmtime time;
        my $file      = $timestamp . '_' . $jira . '_setup_orchard_client_' . $whoami . '.sql';
        my $path      = $base . '/' . $file;
        print ">>> Writing orchard_client init script:   $path\n";
        open( my $fh, '>>', $path ) or die "Could not open file '$path' $!";
        print $fh "INSERT INTO orchard_client(client_id,start_period) VALUES " . join(', ', @clientList) . ";\n";
        close $fh;

    } else {
        print "  ** no Orchard sync client(s) detected\n";
    }

}

sub outputCommonRSDBStaticListYml {
    my $args = shift;

    my $_clientID = $args->[0]{id};
    _printHeader("Here are the changes for common/lib/Common/RSDB/StaticList.yml");
    my $pc = $_clientID - 1;
    print "\n  * Added entry to config file\n\n";
    print "$pc:\n";
    print "  . . .\n";

    foreach my $c ( @$args ) {
        my $clientID = $c->{id};
        my $dbName   = $c->{dbName};
        my $dbHost   = $c->{dbHost};
        my $webHost  = $c->{webHost};

        print "$clientID:\n";
        print "  db_name: $dbName\n";
        print "  host_id: $webHost\n";
        print "  server:  $dbHost\n";
        #print "\n\n\n";
    }
} # outputCommonRSDBStaticListYml

sub outputCommonConsts {
    my $args = shift;

    _printHeader("Here are the changes for common/lib/Common/Consts.pm");
    print "\n  * updated CLIENT_SALE_AGG:\n\n";
    print "  \%CLIENT_SALE_AGG =\n  (\n  . . .\n";

    foreach my $c ( @$args ) {
        my $clientID = $c->{id};
        print "        $clientID => {\n";
        print "            period_type   => 'Q',\n";
        print "            priority      => $clientID,\n";
        print "            active        => 1,\n";
        print "            good_sale_min => 75,\n";
        print "        },\n";
    }
} # outputCommonConsts

sub outputClientClient {
    my $args = shift;

    # TODO: Need to check if constant exists and adjust name if so
    #
    _printHeader("Here are the changes for data_classes/lib/Client/Client.pm");
    print "\n  * Added constant(s):\n\n";

    foreach my $c ( @$args ) {
        my $clientID = $c->{id};
        my $codeName = $c->{codeName};
        my $kName = "k" . $codeName;
        print sprintf("use constant %-25s => %d;\n",$kName, $clientID);
    }

    print "\n  * Added entry(ies) to gPreferences:\n\n";
    print "  \%gPreferences =\n  (\n  . . .\n";
    foreach my $c ( @$args ) {
        my $codeName = $c->{codeName};
        my $kName    = "k" . $codeName;
        print "    $kName() => {\n";
        print "         skipFreeTracks   => 1,\n";
        print "         reportFreeTracks => 0,\n";
        print "         codeName         => '$codeName',\n";
        print "    },\n";
    }
} # outputClientClient 

sub outputCreateSitesProduction {
    my $args = shift;
    _printHeader("Here are the changes for dbadmin/bin/create_sites_production.sh");
    print "\n";
    foreach my $c ( @$args ) {
        my $clientID     = $c->{id};
        my $clientName   = $c->{clientName};
        my $dbName       = $c->{dbName};
        my $vhost        = $c->{vhost};
        my $typeMask     = $c->{typeMask};
        my $countryCode  = $c->{countryCode};
        my $defaultPayor = $c->{defaultPayor};
        my $defaultLabel = $c->{defaultLabel};
        #my $serverID     = $c->{serverID};
        my $serverID     = 'db01'; # hard-code so stats will work...

        print "perl /app/tools/dbadmin/bin/setup_site.pl -c $clientID -d $dbName -n $clientName "
           . "-e $vhost -m $typeMask -o $countryCode -y $defaultPayor -L $defaultLabel "
           . "-l en "
           . "-p -s $serverID "
       . "-x\n";
    }
    print "\n\n\n";
} # outputCreateSitesProduction

sub outputCreateSitesStaging {
    my $args = shift;
    _printHeader("Here are the changes for dbadmin/bin/create_sites_staging.sh");
    print "\n";
    foreach my $c ( @$args ) {
        my $clientID     = $c->{id};
        my $clientName   = $c->{clientName};
        my $dbName       = $c->{dbName};
        my $vhost        = $c->{vhost};
        my $typeMask     = $c->{typeMask};
        my $countryCode  = $c->{countryCode};
        my $defaultPayor = $c->{defaultPayor};
        my $defaultLabel = $c->{defaultLabel};
        my $serverID     = $c->{serverID};
        print "perl /app/tools/dbadmin/bin/setup_site.pl -c $clientID -d $dbName -n $clientName "
           . "-e $vhost -m $typeMask -o $countryCode -y $defaultPayor -L $defaultLabel "
           . "-l en "
           . "-x\n";

    }
    print "\n\n\n";
} # outputCreateSitesStaging

sub getClientMask {
    my $modules = shift;

    my $mask = 1; # Everyone gets Digital Advantage

    my %gTypeMasks = (
       'Digital Advantage'           => 1,
       'Artist Royalt(ies|y)'        => 2,
       'Label Royalt(ies|y)'         => 4,
       'Distribution'                => 8,
       'US Mechanical(s)'            => 16,
       'US Mechanical Royalt(ies|y)' => 16,
       'UK Mechanical(s)'            => 32,
       'UK Mechanical Royalt(ies|y)' => 32,
       'CA Mechanical(s)'            => 64,
       'CA Mechanical Royalt(ies|y)' => 64,
    #  'CA Mechanicals'              => 64,
       'Book Publishing'             => 128,
       'Sale Price Validation'       => 256,
    #  'Product Monitoring'          => 512,
       'Payee Portal'                => 1024,
    );
    foreach my $p ( keys %gTypeMasks ) {
        if( $modules =~ /($p)/i ) {
            $mask |= $gTypeMasks{$p};
            #print "D: removing '$1' from '$modules'\n"; # XXX
            $modules =~ s/$1//i;
        }
    }
    $modules =~ s/(\+|,)//g;  # remove any delimiters
    $modules =~ s/^\s+//g;    # remove any leading space
    $modules =~ s/\s+$//g;    # remove any trailing space


    die("ERROR: getClientMask unable to decode '$modules' !!!") if( $mask == 1 || $modules !~ /^\s*$/ );
    $mask;

} #getClientMask

sub getClientDBName {
    my $vhost = shift;
    my $clientDBName = $vhost;
    $clientDBName =~ s/ /_/g;
    $clientDBName =~ s/-/_/g;
    $clientDBName =~ s/,//g;
    $clientDBName =~ s/\.//g;

    #print "D: getClientDBName: dbname($clientDBName)\n";
    return 'C_' . uc $clientDBName;
} # getClientDBName

sub getHosts {
    my $serverID = shift;

    my $dbHost;
    my $webHost;
    if( $serverID =~ /rps01/i )
    {
       $dbHost  = "rpsdb21";
       $webHost = "rpsweb01";
    }
    elsif( $serverID =~ /rps02/i )
    {
       $dbHost  = "rpsdb22";
       $webHost = "rpsweb02";
    }
    elsif( $serverID =~ /rps03/i )
    {
       $dbHost  = "rpsdb23";
       $webHost = "rpsweb03";
    }
    elsif( $serverID =~ /rps04/i )
    {
       $dbHost  = "rpsdb24";
       $webHost = "bpweb01";
    }
    elsif( $serverID =~ /bp01/i )
    {
       $dbHost  = "rpsdb24";
       $webHost = "bpweb01";
    }
    elsif( $serverID =~ /rps05/i )
    {
       $dbHost  = "rpsdb25";
       $webHost = "rpsweb03";
    }
    elsif( $serverID =~ /rps06/i )
    {
       $dbHost  = "rpsdb26";
       $webHost = "rpsweb03";
    }
    elsif( $serverID =~ /rps07/i )
    {
       $dbHost  = "rpsdb27";
       $webHost = "rpsweb03";
    }
    else
    {
       die("Invalid serverID $serverID");
    }
    return ($dbHost, $webHost);
} # getHosts

sub clients {
    my $yaml_path = shift;
    my $yaml = YAML::Syck::LoadFile($yaml_path);
    my $clientID = $yaml->{starting_client_id};
    my $clients = $yaml->{clients};
    return ( \@$clients, $clientID );
}

sub _trim
{
   my($s) = @_;
   $s =~ s/\s+$//;
   return $s;
}

sub _printHeader
{
    my($s) = @_;
    print "___ ## $s\n\n";
}

sub usage
{
    print <<EofUSAGE;

usage: $0 -y sitesettings.yml

example:
$0 -y sitedata.yml > log_sitedata.txt
Takes the settings from the yaml file and generates a checklist of things
to modify in order to implement the new site.

EofUSAGE
}
