#include "updatedatabasedialog.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QScrollBar>
#include <QDateTime>
#include <QFileInfo>
#include <QTimer>

UpdateDatabaseDialog::UpdateDatabaseDialog(const QString &scriptPath,
                                           const QString &dbPath,
                                           const QString &screenshotsDir,
                                           QWidget *parent)
    : QDialog(parent)
    , m_scriptPath(scriptPath)
    , m_dbPath(dbPath)
    , m_screenshotsDir(screenshotsDir)
    , m_process(nullptr)
{
    setWindowTitle(tr("Update Database"));
    setMinimumSize(600, 400);
    // Non-modal: caller uses show(), not exec()
    setWindowModality(Qt::NonModal);

    // ----- Layout -----
    auto *mainLayout = new QVBoxLayout(this);

    m_statusLabel = new QLabel(tr("Starting OCR process…"), this);
    mainLayout->addWidget(m_statusLabel);

    m_progressBar = new QProgressBar(this);
    m_progressBar->setRange(0, 0); // indeterminate
    mainLayout->addWidget(m_progressBar);

    m_logView = new QTextEdit(this);
    m_logView->setReadOnly(true);
    m_logView->setFont(QFont("monospace", 9));
    mainLayout->addWidget(m_logView);

    auto *btnLayout = new QHBoxLayout();
    btnLayout->addStretch();

    m_cancelButton = new QPushButton(tr("Cancel"), this);
    btnLayout->addWidget(m_cancelButton);

    m_closeButton = new QPushButton(tr("Close"), this);
    m_closeButton->setEnabled(false);
    btnLayout->addWidget(m_closeButton);

    mainLayout->addLayout(btnLayout);

    connect(m_cancelButton, &QPushButton::clicked, this, &UpdateDatabaseDialog::onCancelClicked);
    connect(m_closeButton,  &QPushButton::clicked, this, &QDialog::accept);

    startProcess();
}

UpdateDatabaseDialog::~UpdateDatabaseDialog()
{
    if (m_process && m_process->state() != QProcess::NotRunning) {
        m_process->kill();
        m_process->waitForFinished(3000);
    }
}

void UpdateDatabaseDialog::startProcess()
{
    QFileInfo scriptInfo(m_scriptPath);
    if (!scriptInfo.exists()) {
        appendLog(tr("Error: script not found at %1").arg(m_scriptPath), true);
        m_progressBar->setRange(0, 1);
        m_progressBar->setValue(1);
        m_statusLabel->setText(tr("Failed – script not found."));
        m_cancelButton->setEnabled(false);
        m_closeButton->setEnabled(true);
        return;
    }

    m_process = new QProcess(this);
    m_process->setProcessChannelMode(QProcess::SeparateChannels);

    connect(m_process, &QProcess::readyReadStandardOutput,
            this, &UpdateDatabaseDialog::onReadyReadStdOut);
    connect(m_process, &QProcess::readyReadStandardError,
            this, &UpdateDatabaseDialog::onReadyReadStdErr);
    connect(m_process,
            QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            this, &UpdateDatabaseDialog::onProcessFinished);

    const QStringList args = {
        m_scriptPath,
        "--db",              m_dbPath,
        "--screenshots-dir", m_screenshotsDir
    };

    appendLog(tr("Running: python3 %1").arg(args.join(' ')));
    appendLog(QString());

    m_process->start("python3", args);
}

void UpdateDatabaseDialog::onReadyReadStdOut()
{
    const QString text = QString::fromUtf8(m_process->readAllStandardOutput());
    for (const QString &line : text.split('\n', Qt::SkipEmptyParts))
        appendLog(line);
}

void UpdateDatabaseDialog::onReadyReadStdErr()
{
    const QString text = QString::fromUtf8(m_process->readAllStandardError());
    for (const QString &line : text.split('\n', Qt::SkipEmptyParts))
        appendLog(line, true);
}

void UpdateDatabaseDialog::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
    m_progressBar->setRange(0, 1);
    m_progressBar->setValue(1);
    m_cancelButton->setEnabled(false);
    m_closeButton->setEnabled(true);

    if (exitStatus == QProcess::CrashExit || exitCode != 0) {
        m_statusLabel->setText(tr("OCR process failed (exit code %1).").arg(exitCode));
        appendLog(tr("\nProcess exited with code %1.").arg(exitCode), true);
    } else {
        m_statusLabel->setText(tr("OCR process completed successfully."));
        appendLog(tr("\nDone."));
        emit updateFinished();
    }
}

void UpdateDatabaseDialog::onCancelClicked()
{
    if (m_process && m_process->state() != QProcess::NotRunning) {
        appendLog(tr("\nCancelling…"), true);
        m_cancelButton->setEnabled(false);
        m_statusLabel->setText(tr("Cancelling…"));

        // SIGTERM – Python script's signal handler will clean up and exit
        m_process->terminate();

        // If it hasn't exited after 3 s, send SIGKILL
        QTimer::singleShot(3000, this, [this]() {
            if (m_process && m_process->state() != QProcess::NotRunning) {
                appendLog(tr("Force-killing process…"), true);
                m_process->kill();
            }
        });
    } else {
        reject();
    }
}

void UpdateDatabaseDialog::appendLog(const QString &text, bool isError)
{
    if (isError)
        m_logView->setTextColor(QColor("#cc3333"));
    else
        m_logView->setTextColor(m_logView->palette().color(QPalette::Text));

    m_logView->append(text);

    // Auto-scroll to bottom
    QScrollBar *sb = m_logView->verticalScrollBar();
    sb->setValue(sb->maximum());
}
