/* sqlexport.cc
****************************************************************************************************************
****************************************************************************************************************

    Copyright (C) 2021, 2026 Askar Almatov

    This file is part of Trafficmeter.

    Trafficmeter is free software: you can redistribute it and/or modify it under the terms of the GNU General
    Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    Trafficmeter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License along with Trafficmeter. If not, see
    <http://www.gnu.org/licenses/>.
*/

#include <cstdlib>
#include <sstream>

#include "sqlexport.h"

using namespace iclass;
using namespace iclassdb;
using namespace trafficmeter;

using std::map;
using std::ostream;
using std::ostringstream;
using std::string;

constexpr const char*  DB_NAME_     = "iadmin";
constexpr const char*  DB_USER_     = "tm";
constexpr const char*  DB_PASSWORD_ = "GmndfstwpF";
constexpr const char*  DB_HOST_     = "admin-db";
constexpr const char*  DB_PORT_     = "";

/**************************************************************************************************************/
static string
selectStatement_( const periodt& timeInterval, const string& sender )
{
    ostringstream   oss;

    oss <<
        "SELECT acfetchnet_net "
        "FROM acfetchnettbl "
        "WHERE acfetchnet_date='" << timeInterval.begin().str() << "'::date "
        "AND acfetchnet_achost='" << sender << "';";

    return std::move( oss.str() );
}

/**************************************************************************************************************/
static string
deleteStatement_( const periodt& timeInterval, const string& sender )
{
    ostringstream   oss;

    oss <<
        "DELETE "
        "FROM idailylogtbl "
        "WHERE idailylog_localdate >= '" << timeInterval.begin().str() << "'::date "
        "AND idailylog_localdate < '" << timeInterval.end().str() << "'::date "
        "AND idailylog_ip <<= ANY "
        "( "
            "SELECT acfetchnet_net "
            "FROM acfetchnettbl "
            "WHERE acfetchnet_date = '" << timeInterval.begin().str() << "'::date "
            "AND acfetchnet_achost='" << sender << "' "
        ");";

    return std::move( oss.str() );
}

/**************************************************************************************************************/
static string
insertStatement_( const periodt& timeInterval, ipaddr4t ip, char direction, uintmax_t nBytes )
{
    ostringstream   oss;

    oss <<
        "INSERT INTO idailylogtbl "
        "VALUES "
        "( "
            "'" << ip.str() << "', "
            "'" << direction << "', "
            "'" << timeInterval.begin().str() << "'::date, " <<
            nBytes << " "
        ");";

    return std::move( oss.str() );
}

/**************************************************************************************************************/
SqlExport::SqlExport( const periodt& period, const string& sender ) :
    dbc_( DB_NAME_, DB_USER_, DB_PASSWORD_, DB_HOST_, DB_PORT_ ),
    sender_( sender )
{
    setbegin( period.begin() );
    setend( period.end() );
    saveHosts();
    hideTime();

    if ( !dbc_ )
    {
        return;
    }

    dbresultt   dbr( dbc_, selectStatement_(*this, sender_) );
    long        nTuples = dbr.ntuples();

    for ( int i = 0; i < nTuples; i++ )
    {
        addNetwork( ipnet4t(dbr.at(i,0)) );
    }
}

/**************************************************************************************************************/
bool
SqlExport::isConnected() const
{
    return !!dbc_;
}

/**************************************************************************************************************/
void
SqlExport::fetch()
{
    map<StatQuery::Key,SummaryIo>   summaries;

    StatQuery::fetch( summaries );
    statements_.reserve( (summaries.size() << 1) + 3 );
    statements_.push_back( "BEGIN;" );
    statements_.push_back( deleteStatement_(*this, sender_) );

    for ( const auto& [stat, summary] : summaries )
    {
        statements_.push_back( insertStatement_(*this, stat.ip, 'i', summary.nBytesIn()) );
        statements_.push_back( insertStatement_(*this, stat.ip, 'o', summary.nBytesOut()) );
    }

    statements_.push_back( "COMMIT;" );
}

/**************************************************************************************************************/
long
SqlExport::execute()
{
    long    nTuples = 0;

    for ( const auto& statement : statements_ )
    {
        dbresultt   dbr( dbc_, statement );

        if ( !dbr )
        {
            dbresultt( dbc_, "ROLLBACK;" );
            nTuples = -1;
            break;
        }

        nTuples += dbr.ntuples();
    }

    return nTuples;
}

/**************************************************************************************************************/
void
SqlExport::print( ostream& out )
{
    for ( const auto& statement : statements_ )
    {
        out << statement << '\n';
    }
}
