package Common::DB::Deploy::VersionManager;

use strict;
use warnings;

sub new {
    my ($class, %args) = @_;

    my $self = bless {
        scripts_to_apply => {},
        %args
    }, $class;

    $self->_init();
    return $self;
}

sub logger {
    return shift->{oLogger};
}

sub repositoryManager {
    return shift->{oRepositoryManager};
}

sub databaseManager {
    return shift->{oDatabaseManager};
}

sub commandOption {
    return shift->{oCommandOption};
}

sub getScriptsToApply {
    return shift->{scripts_to_apply};
}

sub _init {
    my $self = shift;

    $self->_initVersionTable();
    $self->_lookForAvailableChanges();

    return 1;
}

sub _initVersionTable {
    my $self = shift;

    my $status = 1;
    unless ( $self->isVersionTableExists ) {
        unless ( $self->commandOption->sync || $self->confirmToCreateVersionTable ) {
            $self->logger->info("Terminate process.");
            exit 0;
        }
        $status = $self->createVersionTable();
    }

    return $status;
}

sub _lookForAvailableChanges {
    my $self = shift;

    my $database = $self->databaseManager->database();
    my $databaseCatalog = $self->databaseManager->databaseCatalog() || '';
    my %appliedScripts = map { $_->{version} => undef } @{ $self->getAppliedScripts() };
    my $hRepositoryScripts = $self->repositoryManager->getRepositoryScripts();

    if ( exists $hRepositoryScripts->{$databaseCatalog} ) {
        while ( my($scriptDir, $hScripsData) = each %{ $hRepositoryScripts->{$databaseCatalog} } ) {
            while ( my($scriptVersion, $scriptName) = each %$hScripsData ) {
                next if exists $appliedScripts{$scriptVersion};
                next if $scriptDir !~ /common|$database$/i;
                $self->{scripts_to_apply}{$scriptVersion} = {
                    dir  => $scriptDir,
                    file => $scriptName,
                };
            }
        }
    }

    return 1;
}

sub confirmToCreateVersionTable {
    my $self = shift;

    my $database = $self->databaseManager->database;
    print "Version table for database '$database' doesn't exist!\nWill be applied all the scripts!\n";
    print "Are you sure want to continue (y/n) ? ";

    $| = 1;
    my $answer = <STDIN>;
    chomp $answer;

    return $answer && lc($answer) =~ /^y|yes$/ ? 1 : 0;
}


sub isVersionTableExists {
    my $self = shift;

    my @results = $self->databaseManager->select(
        q/SHOW TABLES LIKE ?/,
        $self->databaseManager->tableName,
    );

    return scalar @results;
}

sub createVersionTable {
    my $self = shift;

    my $database = $self->databaseManager->database;
    $self->logger->info("Create version table for the database '$database'.");

    $self->databaseManager->query(
        'CREATE TABLE `'. $self->databaseManager->tableName .'` (
            version VARCHAR(30) NOT NULL,
            script_name VARCHAR(128) NOT NULL,
            finished TIMESTAMP NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
            applied_by VARCHAR(50) NOT NULL,
            PRIMARY KEY (version)
        )'
    );

    return 1;
}

sub getAppliedScripts {
    my $self = shift;

    my @results;

    if ( $self->isVersionTableExists ) {
        @results = $self->databaseManager->select(
            'SELECT version FROM `'. $self->databaseManager->tableName . '`'
        );
    }

    return wantarray ? @results : \@results;
}

sub recordAppliedScript {
    my ($self, $oChangeScript) = @_;

    if ( $self->isVersionTableExists ) {
        $self->databaseManager->query('
            INSERT INTO `'. $self->databaseManager->tableName .'`
                (version, script_name, applied_by)
            VALUES
                (?, ?, USER())
            ',
            $oChangeScript->version(),
            $oChangeScript->fileName(),
        );
    }

    return 1;
}


1;