#include "EditorPanel.h"
#include "EditorTab.h"
#include "CodeEditor.h"
#include "SearchPanel.h"
#include "FileSearchPanel.h"

#include <QFileInfo>
#include <QFile>
#include <QTextDocument>
#include <QTextBlock>

EditorPanel::EditorPanel(Settings *settings, QWidget *parent)
    : QWidget(parent)
    , m_settings(settings)
{
    setupUi();
}

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

    m_tabWidget = new QTabWidget(this);
    m_tabWidget->setTabsClosable(true);
    m_tabWidget->setMovable(true);
    m_tabWidget->setDocumentMode(true);

    m_searchPanel = new SearchPanel(this);
    m_fileSearch  = new FileSearchPanel(this);

    m_layout->addWidget(m_tabWidget, 1);
    m_layout->addWidget(m_searchPanel, 0);
    m_layout->addWidget(m_fileSearch, 0);

    connect(m_tabWidget, &QTabWidget::tabCloseRequested,
            this, &EditorPanel::onTabCloseRequested);

    connect(m_tabWidget, &QTabWidget::currentChanged,
            this, &EditorPanel::onCurrentTabChanged);

    connect(m_fileSearch, &FileSearchPanel::fileLineRequested,
            this, &EditorPanel::goToLine);
}

// ---------------------------------------------------------------------------
// Hilfsmethoden
// ---------------------------------------------------------------------------
EditorTab *EditorPanel::currentTab() const
{
    return qobject_cast<EditorTab *>(m_tabWidget->currentWidget());
}

int EditorPanel::findTabForFile(const QString &filePath) const
{
    EditorTab *tab = m_openTabs.value(filePath, nullptr);
    return tab ? m_tabWidget->indexOf(tab) : -1;
}

// ---------------------------------------------------------------------------
// Öffentliche Slots
// ---------------------------------------------------------------------------
void EditorPanel::openFile(const QString &filePath)
{
    const int existing = findTabForFile(filePath);
    if (existing != -1)
    {
        m_tabWidget->setCurrentIndex(existing);
        return;
    }

    EditorTab *tab = new EditorTab(filePath, m_settings, m_tabWidget);
    const int index = m_tabWidget->addTab(tab, tab->fileName());
    m_tabWidget->setCurrentIndex(index);
    m_tabWidget->setTabToolTip(index, filePath);
    m_openTabs.insert(filePath, tab);

    // Änderungsindikator im Tab-Titel (● = ungespeichert)
    connect(tab->editor()->document(), &QTextDocument::modificationChanged,
            this, [this, tab](bool modified)
    {
        const int idx = m_tabWidget->indexOf(tab);
        if (idx == -1)
        {
            return;
        }
        const QString name = QFileInfo(tab->filePath()).fileName();
        m_tabWidget->setTabText(idx, modified ? "● " + name : name);
    });

    // Tab-Titel nach "Speichern unter" aktualisieren (neuer Dateiname, kein Punkt)
    connect(tab->editor(), &CodeEditor::fileSaved, this, [this, tab](const QString &savedPath)
    {
        const int idx = m_tabWidget->indexOf(tab);
        if (idx != -1)
        {
            m_tabWidget->setTabText(idx, QFileInfo(savedPath).fileName());
            m_tabWidget->setTabToolTip(idx, savedPath);
        }
        emit currentFileSaved(savedPath);
    });
}

void EditorPanel::saveCurrentFile()
{
    if (EditorTab *tab = currentTab())
    {
        tab->save();
    }
}

void EditorPanel::saveCurrentFileAs()
{
    if (EditorTab *tab = currentTab())
    {
        tab->saveAs();
    }
}

void EditorPanel::saveAllFiles()
{
    for (int i = 0; i < m_tabWidget->count(); ++i)
    {
        EditorTab *tab = qobject_cast<EditorTab *>(m_tabWidget->widget(i));
        if (tab && tab->isModified())
        {
            tab->save();
        }
    }
}

void EditorPanel::showSearchPanel()
{
    m_fileSearch->hide();
    m_searchPanel->activate();
}

void EditorPanel::showFileSearchPanel()
{
    m_searchPanel->hide();
    m_fileSearch->activate();
}

void EditorPanel::setSearchRoot(const QString &path)
{
    m_fileSearch->setSearchRoot(path);
}

void EditorPanel::goToLine(const QString &filePath, int line)
{
    // Datei öffnen falls noch nicht geöffnet
    openFile(filePath);

    EditorTab *tab = m_openTabs.value(filePath, nullptr);
    if (!tab)
    {
        return;
    }

    m_tabWidget->setCurrentWidget(tab);

    // Zur gewünschten Zeile springen
    CodeEditor *editor = tab->editor();
    QTextBlock block = editor->document()->findBlockByLineNumber(line - 1);
    if (block.isValid())
    {
        QTextCursor cursor(block);
        cursor.movePosition(QTextCursor::StartOfBlock);
        editor->setTextCursor(cursor);
        editor->centerCursor();
        editor->setFocus();
    }
}

QStringList EditorPanel::openFilePaths() const
{
    QStringList paths;
    for (int i = 0; i < m_tabWidget->count(); ++i)
    {
        EditorTab *tab = qobject_cast<EditorTab *>(m_tabWidget->widget(i));
        if (tab)
        {
            paths.append(tab->filePath());
        }
    }
    return paths;
}

QString EditorPanel::activeFilePath() const
{
    EditorTab *tab = currentTab();
    return tab ? tab->filePath() : QString();
}

void EditorPanel::restoreSession(const QStringList &files, const QString &activeFile)
{
    for (const QString &path : files)
    {
        if (QFile::exists(path))
        {
            openFile(path);
        }
    }

    // Aktiven Tab wiederherstellen
    if (!activeFile.isEmpty())
    {
        const int idx = findTabForFile(activeFile);
        if (idx != -1)
        {
            m_tabWidget->setCurrentIndex(idx);
        }
    }
}

void EditorPanel::undo()
{
    if (EditorTab *tab = currentTab())
    {
        tab->editor()->undo();
    }
}

void EditorPanel::redo()
{
    if (EditorTab *tab = currentTab())
    {
        tab->editor()->redo();
    }
}

// ---------------------------------------------------------------------------
// Private Slots
// ---------------------------------------------------------------------------
void EditorPanel::onTabCloseRequested(int index)
{
    EditorTab *tab = qobject_cast<EditorTab *>(m_tabWidget->widget(index));
    if (!tab)
    {
        return;
    }

    m_openTabs.remove(tab->filePath());
    m_tabWidget->removeTab(index);
    tab->deleteLater();

    m_searchPanel->setEditor(currentTab() ? currentTab()->editor() : nullptr);
}

void EditorPanel::onCurrentTabChanged(int /*index*/)
{
    EditorTab *tab = currentTab();
    m_searchPanel->setEditor(tab ? tab->editor() : nullptr);
}
