#include "FileTreePanel.h"

#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QInputDialog>
#include <QMessageBox>
#include <QPoint>

FileTreePanel::FileTreePanel(QWidget *parent)
    : QWidget(parent)
{
    setupUi();
}

// ---------------------------------------------------------------------------
// Setup
// ---------------------------------------------------------------------------
void FileTreePanel::setupUi()
{
    m_layout = new QVBoxLayout(this);
    m_layout->setContentsMargins(0, 0, 0, 0);
    m_layout->setSpacing(0);

    // Small header label showing the project name
    m_label = new QLabel(tr("Kein Projekt geöffnet"), this);
    m_label->setContentsMargins(6, 4, 6, 4);
    m_label->setStyleSheet("font-weight: bold; background: palette(mid);");
    m_label->setWordWrap(true);
    m_layout->addWidget(m_label);

    // File system model – show only the project subtree
    m_model = new QFileSystemModel(this);
    m_model->setReadOnly(false);
    m_model->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);

    // Tree view
    m_tree = new QTreeView(this);
    m_tree->setModel(m_model);
    m_tree->setAnimated(true);
    m_tree->setIndentation(16);
    m_tree->setSortingEnabled(true);
    m_tree->sortByColumn(0, Qt::AscendingOrder);
    m_tree->setEditTriggers(QAbstractItemView::NoEditTriggers);
    m_tree->setHeaderHidden(true);
    m_tree->setContextMenuPolicy(Qt::CustomContextMenu);

    // Hide all columns except the file name
    for (int col = 1; col < m_model->columnCount(); ++col)
    {
        m_tree->hideColumn(col);
    }

    m_layout->addWidget(m_tree);

    connect(m_tree, &QTreeView::activated,
            this, &FileTreePanel::onItemActivated);

    connect(m_tree, &QTreeView::customContextMenuRequested,
            this, &FileTreePanel::onContextMenuRequested);
}

// ---------------------------------------------------------------------------
// Public interface
// ---------------------------------------------------------------------------
void FileTreePanel::setRootPath(const QString &path)
{
    const QModelIndex root = m_model->setRootPath(path);
    m_tree->setRootIndex(root);

    const QString projectName = QDir(path).dirName();
    m_label->setText(projectName.isEmpty() ? path : projectName);
}

void FileTreePanel::clearRoot()
{
    m_model->setRootPath(QString());
    m_tree->setRootIndex(QModelIndex());
    m_label->setText(tr("Kein Projekt geöffnet"));
}

void FileTreePanel::triggerNewFile()
{
    onNewFile();
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
QString FileTreePanel::selectedDirectory() const
{
    const QModelIndex index = m_tree->currentIndex();
    if (!index.isValid())
    {
        return m_model->rootPath();
    }

    const QString path = m_model->filePath(index);
    const QFileInfo info(path);
    return info.isDir() ? path : info.absolutePath();
}

// ---------------------------------------------------------------------------
// Slots
// ---------------------------------------------------------------------------
void FileTreePanel::onItemActivated(const QModelIndex &index)
{
    const QString path = m_model->filePath(index);
    const QFileInfo info(path);

    if (info.isFile())
    {
        emit fileActivated(path);
    }
}

void FileTreePanel::onContextMenuRequested(const QPoint &pos)
{
    QMenu menu(this);

    QAction *actNewFile   = menu.addAction(tr("Neue Datei…"));
    QAction *actNewFolder = menu.addAction(tr("Neuer Ordner…"));
    menu.addSeparator();
    QAction *actDelete    = menu.addAction(tr("Löschen"));

    // Disable delete if nothing is selected
    const QModelIndex index = m_tree->indexAt(pos);
    actDelete->setEnabled(index.isValid());

    QAction *chosen = menu.exec(m_tree->viewport()->mapToGlobal(pos));

    if (chosen == actNewFile)
    {
        onNewFile();
    }
    else if (chosen == actNewFolder)
    {
        onNewFolder();
    }
    else if (chosen == actDelete)
    {
        onDeleteEntry();
    }
}

void FileTreePanel::onNewFile()
{
    const QString dir = selectedDirectory();
    if (dir.isEmpty())
    {
        return;
    }

    bool ok = false;
    const QString name = QInputDialog::getText(
        this,
        tr("Neue Datei"),
        tr("Dateiname:"),
        QLineEdit::Normal,
        QString(),
        &ok
    );

    if (!ok || name.trimmed().isEmpty())
    {
        return;
    }

    const QString filePath = QDir(dir).filePath(name.trimmed());

    if (QFile::exists(filePath))
    {
        QMessageBox::warning(this, tr("Neue Datei"),
            tr("Eine Datei mit diesem Namen existiert bereits:\n%1").arg(filePath));
        return;
    }

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly))
    {
        QMessageBox::critical(this, tr("Neue Datei"),
            tr("Datei konnte nicht angelegt werden:\n%1").arg(filePath));
        return;
    }
    file.close();

    emit fileCreated(filePath);

    // Select the new file in the tree
    const QModelIndex newIndex = m_model->index(filePath);
    m_tree->setCurrentIndex(newIndex);
    m_tree->scrollTo(newIndex);
}

void FileTreePanel::onNewFolder()
{
    const QString dir = selectedDirectory();
    if (dir.isEmpty())
    {
        return;
    }

    bool ok = false;
    const QString name = QInputDialog::getText(
        this,
        tr("Neuer Ordner"),
        tr("Ordnername:"),
        QLineEdit::Normal,
        QString(),
        &ok
    );

    if (!ok || name.trimmed().isEmpty())
    {
        return;
    }

    if (!QDir(dir).mkdir(name.trimmed()))
    {
        QMessageBox::critical(this, tr("Neuer Ordner"),
            tr("Ordner konnte nicht angelegt werden:\n%1")
                .arg(QDir(dir).filePath(name.trimmed())));
    }
}

void FileTreePanel::onDeleteEntry()
{
    const QModelIndex index = m_tree->currentIndex();
    if (!index.isValid())
    {
        return;
    }

    const QString path = m_model->filePath(index);
    const QFileInfo info(path);
    const QString what = info.isDir() ? tr("Ordner") : tr("Datei");

    const auto answer = QMessageBox::question(
        this,
        tr("%1 löschen").arg(what),
        tr("%1 wirklich löschen?\n%2").arg(what, path),
        QMessageBox::Yes | QMessageBox::No,
        QMessageBox::No
    );

    if (answer != QMessageBox::Yes)
    {
        return;
    }

    if (info.isDir())
    {
        QDir(path).removeRecursively();
    }
    else
    {
        QFile::remove(path);
    }
}
