/*
 * iDescriptor: A free and open-source idevice management tool.
 *
 * Copyright (C) 2025 Uncore <https://github.com/uncor3>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "photoimportdialog.h"
#include "httpserver.h"
#include <QApplication>
#include <QDateTime>
#include <QFileInfo>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QPainter>
#include <QPixmap>
#include <QRandomGenerator>
#include <QTimer>
#include <QUrl>
#include <qrencode.h>

PhotoImportDialog::PhotoImportDialog(const QStringList &files, QWidget *parent)
    : QDialog(parent), selectedFiles(files)
{
    setupUI();
    setModal(true);
    resize(600, 600);
    setWindowTitle("Import Photos to iDevice - iDescriptor");
#ifdef WIN32
    setupWinWindow(this);
#endif
}

PhotoImportDialog::~PhotoImportDialog()
{
    if (m_mediaPlayer) {
        m_mediaPlayer->stop();
        delete m_mediaPlayer;
    }
    if (m_httpServer) {
        m_httpServer->stop();
        delete m_httpServer;
    }
}

void PhotoImportDialog::setupUI()
{
    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    // File list
    QLabel *listLabel = new QLabel(
        QString("Files to be served (%1 items):").arg(selectedFiles.size()),
        this);
    mainLayout->addWidget(listLabel);

    fileList = new QListWidget(this);
    fileList->setMaximumHeight(150);
    for (const QString &file : selectedFiles) {
        QFileInfo info(file);
        fileList->addItem(info.fileName());
    }
    mainLayout->addWidget(fileList);

    // Horizontal layout for QR code and instructions
    QHBoxLayout *contentLayout = new QHBoxLayout();

    // QR Code area
    qrCodeLabel = new QLabel(this);
    qrCodeLabel->setAlignment(Qt::AlignCenter);
    qrCodeLabel->setMinimumSize(200, 200);
    qrCodeLabel->setMaximumSize(200, 200);
    qrCodeLabel->setText("QR Code will appear here after starting server");
    contentLayout->addWidget(qrCodeLabel);

    // Instructions container
    QVBoxLayout *instructionContainer = new QVBoxLayout();

    // Stacked widget for switchable instructions
    m_instructionStack = new QStackedWidget(this);
    m_instructionStack->setSizePolicy(QSizePolicy::Expanding,
                                      QSizePolicy::Expanding);

    // Text instructions
    m_instructionLabel = new QLabel("Loading", this);
    m_instructionLabel->setWordWrap(true);
    m_instructionStack->addWidget(m_instructionLabel);

    // Video instructions
    m_instructionVideo = new QVideoWidget(this);
    m_instructionVideo->setMinimumSize(300, 500);
    m_instructionVideo->setSizePolicy(QSizePolicy::Expanding,
                                      QSizePolicy::Expanding);
    m_mediaPlayer = new QMediaPlayer(this);
    m_mediaPlayer->setVideoOutput(m_instructionVideo);
    m_instructionStack->addWidget(m_instructionVideo);

    m_instructionVideo->setAspectRatioMode(
        Qt::AspectRatioMode::KeepAspectRatioByExpanding);
    m_instructionVideo->setStyleSheet(
        "QVideoWidget { background-color: transparent; }");

    instructionContainer->addWidget(m_instructionStack);

    // Toggle button
    m_toggleInstructionButton =
        new QPushButton("Show Video Instructions", this);
    connect(m_toggleInstructionButton, &QPushButton::clicked, this,
            &PhotoImportDialog::toggleInstructionMode);

    instructionContainer->addSpacing(10);

    QHBoxLayout *buttonContainer = new QHBoxLayout();
    buttonContainer->addStretch();
    buttonContainer->addWidget(m_toggleInstructionButton);
    buttonContainer->addStretch();
    instructionContainer->addLayout(buttonContainer);

    contentLayout->addLayout(instructionContainer);
    mainLayout->addLayout(contentLayout);

    // Progress tracking
    m_progressLabel = new QLabel("Download progress will appear here", this);
    m_progressLabel->setVisible(false);
    mainLayout->addWidget(m_progressLabel, Qt::AlignCenter);

    mainLayout->addSpacing(5);

    m_serverAddress = new QLabel("", this);
    m_serverAddress->setVisible(false);
    mainLayout->addWidget(m_serverAddress, Qt::AlignCenter);

    // Buttons
    QHBoxLayout *buttonLayout = new QHBoxLayout();
    m_cancelButton = new QPushButton("Cancel", this);

    buttonLayout->addStretch();
    buttonLayout->addWidget(m_cancelButton);

    mainLayout->addLayout(buttonLayout);

    connect(m_cancelButton, &QPushButton::clicked, this, &QDialog::reject);

    // Setup video looping
    connect(m_mediaPlayer,
            QOverload<QMediaPlayer::MediaStatus>::of(
                &QMediaPlayer::mediaStatusChanged),
            [this](QMediaPlayer::MediaStatus status) {
                if (status == QMediaPlayer::EndOfMedia) {
                    m_mediaPlayer->setPosition(0);
                    m_mediaPlayer->play();
                }
            });

    QTimer::singleShot(0, this, &PhotoImportDialog::init);
}

void PhotoImportDialog::init()
{

    // Create and start HTTP server
    m_httpServer = new HttpServer(this);
    connect(m_httpServer, &HttpServer::serverStarted, this,
            &PhotoImportDialog::onServerStarted);
    connect(m_httpServer, &HttpServer::serverError, this,
            &PhotoImportDialog::onServerError);
    connect(m_httpServer, &HttpServer::downloadProgress, this,
            &PhotoImportDialog::onDownloadProgress);

    m_httpServer->start(selectedFiles);
}

void PhotoImportDialog::onServerStarted()
{

    QString localIP = HttpServer::getLocalIP();
    int port = m_httpServer->getPort();
    QString jsonFileName = m_httpServer->getJsonFileName();
    QString url =
        QString("https://idescriptor.github.io/import?local=%1&port=%2&file=%3")
            .arg(localIP)
            .arg(port)
            .arg(jsonFileName);
    qDebug() << "Server url" << url;

    generateQRCode(url);

    m_instructionLabel->setText(
        "Instructions on How to Import\n\n1.Scan the QR code to open the "
        "web interface\n2.Click on \"Copy Server Address\"\n3.Click on "
        "\"Import and Run Shortcut\" if you have not installed the "
        "shortcut before or \"Run Shortcut\" if you have installed it "
        "before. \n4.Run the shortcut in the Shortcuts app. Once the "
        "shortcut imports to your device, it will automatically run "
        "\"Photos app\" \n\n Switch to video tutorial if you want to see a "
        "video tutorial.");

    m_mediaPlayer->setSource(
        QUrl("qrc:/resources/wireless-gallery-import.mp4"));

    m_progressLabel->setText("Waiting for downloads...");
    m_progressLabel->setVisible(true);

    m_serverAddress->setText(
        QString("Server started at %1:%2").arg(localIP).arg(port));
    m_serverAddress->setVisible(true);
}

void PhotoImportDialog::onDownloadProgress(const QString &fileName,
                                           int bytesDownloaded, int totalBytes)
{
    // TODO: bring in a progress bar each item
    m_progressLabel->setText(QString("Downloaded: %1 (%2 KB)")
                                 .arg(fileName)
                                 .arg(bytesDownloaded / 1024));
}

void PhotoImportDialog::onServerError(const QString &error)
{
    m_cancelButton->setEnabled(true);

    QMessageBox::critical(this, "Server Error",
                          QString("Failed to start server: %1").arg(error));
    QDialog::reject();
}

void PhotoImportDialog::generateQRCode(const QString &url)
{
    QRcode *qrcode = QRcode_encodeString(url.toUtf8().constData(), 0,
                                         QR_ECLEVEL_M, QR_MODE_8, 1);
    if (!qrcode) {
        qrCodeLabel->setText("Failed to generate QR code");
        return;
    }

    int qrSize = 200;
    int qrWidth = qrcode->width;
    int scale = qrSize / qrWidth;
    if (scale < 1)
        scale = 1;

    QPixmap qrPixmap(qrWidth * scale, qrWidth * scale);
    qrPixmap.fill(Qt::white);

    QPainter painter(&qrPixmap);
    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::black);

    for (int y = 0; y < qrWidth; y++) {
        for (int x = 0; x < qrWidth; x++) {
            if (qrcode->data[y * qrWidth + x] & 1) {
                QRect rect(x * scale, y * scale, scale, scale);
                painter.drawRect(rect);
            }
        }
    }

    qrCodeLabel->setPixmap(qrPixmap);
    QRcode_free(qrcode);
}

void PhotoImportDialog::toggleInstructionMode()
{
    if (m_instructionStack->currentIndex() == 0) {
        // Switch to video
        m_instructionStack->setCurrentIndex(1);
        m_toggleInstructionButton->setText("Show Text Instructions");
        m_mediaPlayer->play();
    } else {
        // Switch to text
        m_instructionStack->setCurrentIndex(0);
        m_toggleInstructionButton->setText("Show Video Instructions");
        m_mediaPlayer->stop();
    }
}
