/***************************************************************************
 *   Copyright (C) 2025 by santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#include <QSettings>
#include <QPushButton>
#include <QNetworkReply>

#include "installer.h"
#include "componentlist.h"
#include "installitem.h"
#include "mainwindow.h"
#include "qzipreader.h"
#include "utils.h"

Installer::Installer( QWidget* parent )
         : QWidget( parent )
{
    setupUi(this); 

    m_checkUpdates = true;  //false; 
    m_updated = false; 
    m_changed = false; 

    m_installItem = nullptr; 

    installTable->horizontalHeader()->setStretchLastSection( true ); 

    m_compsUrl = "https://simulide.com/p/direct_downloads/components/"; 

    m_compsDir.setPath( MainWindow::self()->getConfigPath("components") ); 
    if( !m_compsDir.exists() ) m_compsDir.mkpath("."); 

    loadList(); 

    QSettings* settings = MainWindow::self()->settings(); 
    QStringList installedList = settings->value("library/installed").toString().split(","); 

    for( QString itemStr : installedList )
    {
        if( itemStr.isEmpty() ) continue; 

        QStringList list = itemStr.split("; "); 
        if( list.size() < 2 ) return; 
        QString name = list.first(); 

        InstallItem* item = m_items.value( name ); 
        if( !item ) continue; 

        QString version = "2507102250" ; //list.at(1); //
        int64_t v = version.toLongLong(); 
        item->m_version = v; 
        item->shouldUpdate( v ); 

        qDebug() << "Installer::Installer" << name << version; 

        m_installed.insert( item->m_name, v ); 
    }
}

void Installer::loadList()
{
    QString compFile = m_compsDir.filePath("components.txt"); 
    QString replyStr = fileToString( compFile, "Installer::loadList" ); 

    QStringList setList = replyStr.split("\n");  // List of Component Sets

    m_changed = false; 
    int row = 0; 
    for( QString itemStr : setList )
    {
        if( itemStr.isEmpty() ) continue; 
        //qDebug() <<"Installer::loadList"<< itemStr; 

        InstallItem* item = nullptr; 

        QStringList list = itemStr.split("; "); 
        QString name = list.first(); 

        if( m_installed.contains( name ) )
        {
            item = m_items.value( name ); 

            if( item && list.size() > 3 ) {
                QString v = list.at(3); 
                v.remove(0,1); 
                //qDebug() << "Installer::loadList updated" << name << v << item->m_version; 

                if( item->shouldUpdate( v.toLongLong() ) ) m_changed = true; 
            }
        }
        else if( m_items.contains( name ) )
        {
            item = m_items.value( name ); 
        }
        else
        {
            item = new InstallItem( this, itemStr ); 

            item->shouldUpdate( 0 ); 

            m_items.insert( item->m_name, item ); 

            installTable->insertRow( row ); 
            installTable->setCellWidget( row, 0, item ); 

            m_changed = true; 
        }
        float scale = MainWindow::self()->fontScale(); 

        if( item->m_file.isEmpty() ) installTable->setRowHeight( row, 25*scale ); 
        else                         installTable->setRowHeight( row, 60*scale ); 

        row++; 
    }
    installTable->setRowCount( row ); 
    m_updated = true; 
}

void Installer::loadInstalled()
{
    for( QString item : m_installed.keys() )
    {
        QDir compSetDir = m_compsDir; 
        compSetDir.cd( item ); 
        ComponentList::self()->LoadCompSetAt( compSetDir ); 
        QStringList itemList = ComponentList::self()->getxmlItems(); 
        m_groupItemList.insert( item, itemList ); 
    }
}

void Installer::checkForUpdates( QString url )
{
    if( !m_checkUpdates ) return; 

    //QString version = MainWindow::self()->settings()->value("library/version").toString(); 
    //qDebug() << "version" << version; 
    qDebug() << "Checking for Updates..."; 

    if( url.isEmpty() ) url = m_compsUrl+"dloadset.php?file=components.txt"; 
    QNetworkRequest request( url ); 

    request.setAttribute( QNetworkRequest::RedirectPolicyAttribute
                        , QNetworkRequest::NoLessSafeRedirectPolicy ); 

    request.setTransferTimeout( 5000 ); 

    m_reply = m_manager.get( request ); 

    QObject::connect( m_reply, &QNetworkReply::finished,
                     [=](){ updtReady();  } ); 
}

void Installer::updtReady()
{
    if( m_reply->error() == QNetworkReply::NoError )
    {
        QString compFile = m_compsDir.filePath( "components.txt" ); 
        QFile file( compFile ); 
        if( file.exists() ) QFile::remove( compFile ); 

        if( file.open( QIODevice::WriteOnly | QIODevice::Append ))
        {
            file.write( m_reply->readAll() ); 
            file.close(); 

            loadList(); 

            if( m_changed ) qDebug() << "Installer: Updates available"; 
            else            qDebug() << "Installer: Up to date"; 
        }else{
            qDebug() << "Installer::updtReady ERROR: can't write file" << compFile ; 
            m_installItem = nullptr; 
        }
    }
    else qDebug() << "Installer::updtReady ERROR:" << m_reply->errorString();  // There was a network error

    m_reply->close(); 
}

void Installer::installItem( QString itemName )
{
    InstallItem* item = m_items.value( itemName ); 

    if( !item->m_depends.isEmpty() && !m_installed.contains( item->m_depends ) )
    {
        m_nextItem = itemName; 
        itemName = item->m_depends; 
        item = m_items.value( itemName ); 
    }
    else m_nextItem.clear(); 

    if( !item ) return; 

    qDebug() << "Installing Component Set:" << itemName; 

    QString url = m_compsUrl+"dloadset.php?file="+item->m_file; 
    QNetworkRequest request( url ); 

    request.setAttribute( QNetworkRequest::RedirectPolicyAttribute
                        , QNetworkRequest::NoLessSafeRedirectPolicy ); 

    request.setTransferTimeout( 5000 ); 

    m_reply = m_manager.get( request ); 

    QObject::connect( m_reply, &QNetworkReply::finished,
                     [=](){ itemDataReady();  } ); 

    m_installItem = item; 
}

void Installer::unInstallItem( QString itemName )
{
    QDir compSetDir = m_compsDir; 
    compSetDir.cd( itemName ); 
    compSetDir.removeRecursively(); 
    m_installed.remove( itemName ); 

    ComponentList::self()->createList(); 
}

void Installer::itemDataReady()
{
    bool error = true; 
    if( m_reply->error() == QNetworkReply::NoError )
    {
        error = false; 
    }
    else qDebug() << "Installer::itemDataReady QNetworkReply ERROR";  // There was a network error

    m_reply->close(); 

    if( !error )
    {
        QString zipFile = m_compsDir.filePath( m_installItem->m_file ); 

        QFile file( zipFile ); 
        if( file.exists() ) QFile::remove( zipFile ); 

        if( file.open( QIODevice::WriteOnly | QIODevice::Append ))
        {
            file.write( m_reply->readAll() ); 
            file.close(); 
        }else{
            qDebug() << "Installer::itemDataReady ERROR: can't write file" << zipFile ; 
            m_installItem = nullptr; 
            return; 
        }

        //QString setDir =m_compsDir.absolutePath()+ m_installItem->m_name; 
        qZipReader qZip( zipFile ); 
        bool isExtracted = qZip.extractAll( m_compsDir.absolutePath() ); 

        if( isExtracted )
        {
            QDir compSetDir = m_compsDir; 
            compSetDir.cd( m_installItem->m_name ); 
            ComponentList::self()->LoadCompSetAt( compSetDir ); 

            m_installed.insert( m_installItem->m_name, m_installItem->m_versionNext ); 
            qDebug() << m_installItem->m_name <<"Installed"; 
        }
        else qDebug() << "Installer::itemDataReady ERROR extracting" << zipFile ; 

        QFile::remove( zipFile ); 
    }
    m_installItem = nullptr; 
    if( !m_nextItem.isEmpty() ) installItem( m_nextItem ); 
}

void Installer::on_updtButton_clicked()
{
    checkForUpdates(); 
}

void Installer::writeSettings()
{
    QString installed;  // = "Arduino,AVR,PIC,MCS51,MCS65,Z80,Analog,74,Digipot,Tools"; 

    for( QString itemName : m_installed.keys() )
    {
        InstallItem* item = m_items.value( itemName ); 
        installed += item->toString()+","; 
    }
    QSettings* settings = MainWindow::self()->settings(); 
    settings->setValue("library/installed", installed ); 
}
//#include moc_installer.cpp
