#!/usr/bin/perl

use warnings;
use strict;
use diagnostics;

use DBI;

binmode(STDOUT, ":utf8");

sub insert_formatter {
    my $table = shift;
    my @columns = @_;

    return sub {
        my $v = shift;

        print qq|INSERT INTO $table (| . join(', ', @columns) . qq|) VALUES|
            . "    (" . join(
            ", ",
            map { defined $_ ? "'$_'" : 'NULL' }
            map { $v->{$_} } @columns
            ) . ");\n"
    }
}

sub nv { return (defined $_[0]) ? $_[0] : 'NULL'; }
sub ns { return (defined $_[0]) ? "'$_[0]'" : 'NULL'; }
sub nb { return (defined $_[0]) ? ($_[0] ? "true" : "false") : 'NULL' }


sub Print_SQL_Insert {
    my $dbh = shift;
    my $qry = shift;
    my $formatter = shift;

    my $sth = $dbh->prepare( $qry ) or die "Unable to prepare statement: $dbh->errstr\n";
    $sth->execute() or die "Unable to execute statement: $sth->errstr\n";

    for my $row (@{ $sth->fetchall_arrayref({}) }) {
        $formatter->($row)
    }
}

# use environment variables for authentication
my $dbh = DBI->connect('dbi:Pg:', undef, undef)
    or die "Unable to connect: $DBI::errstr\n";

print '
-- Create the entire COA in 1 transaction

BEGIN;

';

print "-- HEADINGS DEFINITION\n";
my $query = qq|
    select h.id, h.accno, h.parent_id, h.description
        from account_heading_tree t
    join account_heading h on t.id = h.id
        order by level asc, t.accno asc
|;
Print_SQL_Insert( $dbh, $query, sub {
    my $v = shift;
    print sprintf(qq|SELECT account_heading_save(NULL, %s, %s, %s);\n|,
                  ns($v->{accno}), ns($v->{description}), nv($v->{parent_id})
        );
    });


print "\n\n\n-- GIFI DEFINITION (need gifi before account creation)\n";
$query = qq|
    select * from gifi order by accno
|;
Print_SQL_Insert( $dbh, $query, insert_formatter( 'gifi', qw|accno description| ) );


print "\n\n\n-- ACCOUNTS DEFINITION\n";
$query = qq|
    select r.id as id, a.accno, a.category, a.is_temp, a.gifi_accno as gifi_accno, coalesce(r.link,'') as link, h.accno as heading_accno, contra, tax, obsolete, r.description as description from report__coa() r join account a using (id) left join account_heading h on a.heading = h.id where not is_heading order by a.accno
|;
Print_SQL_Insert( $dbh, $query, sub {
    my $v = shift;
    print sprintf(qq|SELECT account__save(NULL, %s, %s, %s, %s, %s, %s, %s, string_to_array(%s, ':'), %s, %s);\n|,
                  ns($v->{accno}),ns($v->{description}),ns($v->{category}),
                  ns($v->{gifi_accno}), "(select id from account_heading where accno = '$v->{heading_accno}')",
                  nb($v->{contra}), nb($v->{tax}), ns($v->{link}), nb($v->{obsolete}), nb($v->{is_temp}));
                  });


print "\n\n\n-- CUSTOM ACCOUNT LINK DEFINITION\n";
$query = qq|
    select * from account_link_description where custom
|;
Print_SQL_Insert( $dbh, $query, insert_formatter( 'account_link_description', qw|description summary custom| ) );


print "\n\n\n-- TAX DEFINITION\n";
$query = qq#
    select * from tax join account a on tax.chart_id = a.id
#;
Print_SQL_Insert( $dbh, $query, sub {
    my $v = shift;
    print sprintf(qq|INSERT INTO tax (chart_id,rate) VALUES ((SELECT id FROM account WHERE accno = %s), %s);\n|,
                  ns($v->{accno}), ns($v->{rate}));
                  });


print "\n\n\n-- CURRENCIES\n";
$query = qq#
    select * from currency
#;
Print_SQL_Insert( $dbh, $query, insert_formatter( 'currency', qw|curr description| ) );


print "\n\n\n-- SET UP DEFAULTS\n";
$query = qq|
    select * from defaults
        where setting_key in ('inventory_accno_id',
                       'income_accno_id',
                       'expense_accno_id',
                       'fxgain_accno_id',
                       'fxloss_accno_id',
                       'earn_id',
                       'curr',
                       'weightunit',
                       'default_language',
                       'separate_duties',
                       'lock_description',
                       'gapless_ar',
                       'check_prefix',
                       'vclimit',
                       'decimal_places',
                       'show_creditlimit',
                       'session_timeout',
                       'password_duration',
                       'format',
                       'default_country'
                       );
|;
( my $delete_query = $query ) =~ s/select \*/delete/;
print "-- FIRST Delete the Keys we intend to set\n";
print "$delete_query\n";
print "-- NOW ACTUALLY SET the KEYS\n";
Print_SQL_Insert( $dbh, $query, insert_formatter( 'defaults', qw|setting_key value| ) );

print "\n\n\n-- SET UP DEFAULTS that require Lookups\n";
print "-- FIRST Delete the Keys we intend to set\n\n";
$delete_query = qq|delete from defaults where setting_key in ('default_country');|;
print "$delete_query\n";
print "-- NOW ACTUALLY SET the KEYS\n";
$query = qq|
    select C.short_name FROM defaults D
        INNER JOIN country C on D.value = C.id::text
        WHERE setting_key = 'default_country';
|;
my $sth = $dbh->prepare( $query ) or die "Unable to prepare statement: $dbh->errstr\n";
$sth->execute() or die "Unable to execute statement: $sth->errstr\n";

my $default_country = $sth->fetchrow_array;

print "INSERT INTO defaults (value, setting_key ) SELECT id::text, 'default_country' from country WHERE short_name = '$default_country';";

print '

-- END of transaction
COMMIT;

';

