#include "formbudget.h"
#include "ui_formbudget.h"
#include "qmtreeview.h"
#include "treemodel.h"
#include "treeitem.h"
#include "mapplication.h"

#include "../src/elementtype.h"
#include "../dao/elementdao.h"

#include "widgetcomboboxpopuptable.h"

#include "itemnumberdelegate.h"
#include "itemtextdelegate.h"
#include "itemtextpopupdelegate.h"
#include "itemcomboboxdelegate.h"

#include <QStringList>
#include <QFile>
#include <QAction>
#include <QtSql>
#include "../dao/budgetdao.h"
#include "utils/dbutils.h"

formBudget::formBudget(QString aID, int amEditMode, QWidget *parent) :
    formBase(aID, amEditMode, parent),
    ui(new Ui::formBudget),
    m_changed(false)
{
    ui->setupUi(this);
    setupTreeView();
    setupConnections();

    // Prueba:
    connect(dApp, &QApplication::focusChanged, this, [=](QWidget* old, QWidget* now)
    {
        //qDebug() << "old: " << old << "\n" << "new: " << now;
        if (!this->isAncestorOf(old))
            qDebug() << "Se deshabilita la toolbox";

        //Q_UNUSED(old);
        //if (now != this && !this->isAncestorOf(now))
        if (now == this && !this->isAncestorOf(now))
        {
            //hide();
            qDebug() << "Se habilita la toolbox";
        }
    });

    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    if (qry.exec(QString("SELECT ID FROM SALEPROPOSAL ORDER BY ID DESC LIMIT 1;")))
    {
        int val = 0;
        while(qry.next())
            val = qry.value(qry.record().indexOf("ID")).toInt();

        ui->editCode->setText(QString("(PRO%1)").arg(val + 1));
    }

    dApp->Enterprise().close();

    // Connect form fields to track changes
    connect(ui->editTitle, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
    connect(ui->editClientCode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &formBudget::onAnyChange);
    connect(ui->editClientName, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
    connect(ui->editProjectCode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &formBudget::onAnyChange);
    connect(ui->editProjectName, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
    connect(ui->editCost, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
    connect(ui->editCost, &QLineEdit::textChanged, this, &formBudget::updateMargin);
    connect(ui->editPrice, &QLineEdit::textChanged, this, &formBudget::onAnyChange);
    connect(ui->editPrice, &QLineEdit::textChanged, this, &formBudget::updateMargin);
    connect(ui->editdateCreated, &QDateEdit::dateChanged, this, &formBudget::onAnyChange);
    connect(ui->editdateValidUntill, &QDateEdit::dateChanged, this, &formBudget::onAnyChange);
    connect(ui->editVersion, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &formBudget::onAnyChange);
}


formBudget::~formBudget()
{
    delete ui;
}

void formBudget::setupTreeView()
{
    QStringList headers = {
        tr("Índice"), tr("Código"), tr("Título"), tr("Descripción"),
        tr("Cantidad"), tr("Cantidad total"), tr("Unidad"),
        tr("N. Precio Unitario"), tr("N. Precio Total"), tr("Ganacia"),
        tr("Descuento"), tr("Precio Venta"), tr("Margen"), tr("Tipo"),
        tr("Imprimir"), tr("")
    };

    m_treeModel = new TreeModel(headers, QByteArray(), this);
    ui->treeView->setModel(m_treeModel);

    // Configurar anchos de columna
    QVector<int> widths = {120, 120, 250, 250, 80, 80, 50, 80, 80, 80, 80, 80, 80, 40};
    for (int i = 0; i < widths.size(); ++i) {
        ui->treeView->setColumnWidth(i, widths[i]);
    }

    ui->treeView->setColumnHidden(3, true);

    // Configurar delegados
    setupDelegates();
}

void formBudget::setupDelegates()
{
    // Texto con Popup
    auto* lineTextPopup = new ItemTextPopupDelegate(this);
    ui->treeView->setItemDelegateForColumn(1, lineTextPopup);

    // Texto simple
    auto* lineTextEditor = new ItemTextDelegate(this);
    ui->treeView->setItemDelegateForColumn(0, lineTextEditor);
    ui->treeView->setItemDelegateForColumn(2, lineTextEditor);

    // Números
    auto* doubleNumberEditor = new ItemNumberDelegate(0.0, 999999.99, 0.05, 2, this);
    ui->treeView->setItemDelegateForColumn(4, doubleNumberEditor);
    ui->treeView->setItemDelegateForColumn(7, doubleNumberEditor);
    ui->treeView->setItemDelegateForColumn(9, doubleNumberEditor);
    ui->treeView->setItemDelegateForColumn(10, doubleNumberEditor);

    // Combobox
    auto* comboboxEditor = new ItemComboboxDelegate(this);
    ui->treeView->setItemDelegateForColumn(6, comboboxEditor);

    connect(m_treeModel, &TreeModel::dataChanged,
            this, &formBudget::onModelDataChanged);
}

void formBudget::setupConnections()
{
    connect(ui->buttonInsertRow, &QPushButton::released,
            this, &formBudget::on_buttonInsertRow_released);

    connect(ui->buttonInsertChild, &QPushButton::released,
            this, &formBudget::on_buttonInsertChild_released);

    connect(ui->buttonRemoveRow, &QPushButton::released,
            this, &formBudget::on_buttonRemoveRow_released);

    // ... otras conexiones ...
}

void formBudget::initializeDocument()
{
    if (m_dbUtils.isConnected()) {
        QString lastId = m_dbUtils.getLastDocumentId("SALEPROPOSAL");
        ui->editCode->setText(QString("(PRO%1)").arg(lastId.toInt() + 1));
    }
}

void formBudget::newDocument()
{

}

void formBudget::openDocument(QString id)
{
    formBase::openDocument(id);
    m_changed = false;

    BudgetDAO::Data data;
    if (!BudgetDAO::readByCode(id, data))
        return;

    ui->editCode->setText(data.code);
    ui->editTitle->setText(data.title);
    ui->editVersion->setCurrentText(QString::number(data.version));
    ui->editClientCode->setCurrentText(data.customerCode);
    ui->editClientName->setText(data.customerName);
    ui->editProjectCode->setCurrentText(data.projectCode);
    ui->editProjectName->setText(data.projectTitle);
    ui->editCost->setText(QString::number(data.cost, 'f', 2));
    ui->editPrice->setText(QString::number(data.price, 'f', 2));

    // Cargar líneas
    QVector<BudgetDAO::LineData> lines = BudgetDAO::getLines(data.code);
    QAbstractItemModel *model = ui->treeView->model();
    model->removeRows(0, model->rowCount());

    for (const auto &line : lines) {
        // Insertar fila
        if (!model->insertRow(model->rowCount()))
            continue;
        int row = model->rowCount() - 1;

        model->setData(model->index(row, 0), line.nodeIndex);  // Nodo
        model->setData(model->index(row, 1), line.elementCode);
        model->setData(model->index(row, 2), line.elementTitle);
        model->setData(model->index(row, 3), line.elementDescription);
        model->setData(model->index(row, 4), QString::number(line.elementUnitAmount));
        model->setData(model->index(row, 6), line.elementUnit);
        model->setData(model->index(row, 7), QString::number(line.elementPrice, 'f', 2));
        model->setData(model->index(row, 9), QString::number(line.benefit, 'f', 2));
        model->setData(model->index(row, 10), QString::number(line.discount, 'f', 2));
        model->setData(model->index(row, 13), line.elementType);
    }
}

void formBudget::save()
{
    BudgetDAO::Data data;
    data.type = "PR";
    data.code = ui->editCode->text();
    data.title = ui->editTitle->text();
    data.version = ui->editVersion->currentText().toInt();
    data.customerCode = ui->editClientCode->currentText();
    data.customerName = ui->editClientName->text();
    data.projectCode = ui->editProjectCode->currentText();
    data.projectTitle = ui->editProjectName->text();
    data.cost = ui->editCost->text().toDouble();
    data.price = ui->editPrice->text().toDouble();

    if (mEditMode) {
        BudgetDAO::readByCode(data.code, data);
        data.cost = ui->editCost->text().toDouble();
        data.price = ui->editPrice->text().toDouble();
        BudgetDAO::update(data);
        // Eliminar líneas existentes y re-insertar
        BudgetDAO::removeLines(data.code);
    } else {
        BudgetDAO::create(data);
    }

    // Guardar líneas del treeView
    QAbstractItemModel *model = ui->treeView->model();
    int rowCount = model->rowCount();
    for (int i = 0; i < rowCount; i++) {
        QString elementCode = model->index(i, 1).data().toString();
        if (elementCode.isEmpty()) continue;

        BudgetDAO::LineData line;
        line.saleDocumentCode = data.code;
        line.nodeIndex = model->index(i, 0).data().toString();
        line.elementCode = elementCode;
        line.elementType = model->index(i, 13).data().toString();
        line.elementTitle = model->index(i, 2).data().toString();
        line.elementDescription = model->index(i, 3).data().toString();
        line.elementUnitAmount = model->index(i, 4).data().toDouble();
        line.elementUnit = model->index(i, 6).data().toString();
        line.elementPrice = model->index(i, 7).data().toDouble();
        line.benefit = model->index(i, 9).data().toDouble();
        line.discount = model->index(i, 10).data().toDouble();
        line.version = data.version;

        BudgetDAO::createLine(line);
    }

    m_changed = false;
}

bool formBudget::needsave()
{
    // Basic change tracker implemented via m_changed and UI connections
    return m_changed;
}

void formBudget::setEditMode(bool aMode)
{
    mEditMode = aMode;
}

void formBudget::closeDocument()
{
    // TODO: implementar lógica de cierre
    // Por ahora, solo limpiamos el flag de cambios
    m_changed = false;
}

void formBudget::setLineType(QString type, QModelIndex index)
{
    setCellText(type, index, 13);
}

void formBudget::setCellText(QString val, QModelIndex index, int col)
{
    QAbstractItemModel *model = ui->treeView->model();
    model->setData(model->index(index.row(), col, index.parent()), val);
}

bool formBudget::InsertElement(QString ID, QModelIndex index)
{
    ElementDAO::ElementData element;
    if (!ElementDAO::read(ID, element))
    {
        qDebug() << "Failed to read element:" << ID;
        dApp->Enterprise().close();
        return false;
    }

    setCellText(element.title, index, 2);         // TITLE
    setCellText(element.description, index, 3);   // DESCRIPTION
    setCellText(element.unitId, index, 6);       // UNIT

    if (element.type1 == 0) // Composed element
    {
        QVector<ElementDAO::CompositionItem> composition = ElementDAO::getComposition(ID);
        QAbstractItemModel *treemodel = ui->treeView->model();

        for (int i = 0; i < composition.size(); ++i)
        {
            if(!treemodel->insertRow(treemodel->rowCount(index), treemodel->index(index.row(), 0, index.parent())))
                break;

            qDebug() << treemodel->rowCount(index);

            QModelIndex child = treemodel->index(i, 0, treemodel->index(index.row(), 0, index.parent()));
            setCellText(composition[i].childElementCode, child, 1);
            setCellText(QString::number(composition[i].amount), child, 4);   // AMOUNT
        }
    }
    else
    {
        setCellText(QString::number(element.purchasePrice), index, 7);        // PRICE
    }

    // Replaced switch with elementTypeToString function
    setLineType(elementTypeToString(static_cast<ElementType>(element.type1)), index);

    dApp->Enterprise().close();
    return false;
}

void formBudget::on_buttonValidate_released()
{
    // First, save the current budget data
    save();
    
    // Then, use DAO operations to validate all element references
    // This generates the definitive code by ensuring all elements are resolvable
    bool allValid = true;
    QStringList invalidElements;
    
    QAbstractItemModel *model = ui->treeView->model();
    for (int row = 0; row < model->rowCount(); ++row) {
        QModelIndex index = model->index(row, 1); // Column 1 is element ID
        if (index.isValid()) {
            QString elementId = model->data(index).toString();
            if (!elementId.isEmpty()) {
                ElementDAO::ElementData element;
                if (!ElementDAO::read(elementId, element)) {
                    allValid = false;
                    invalidElements.append(elementId);
                }
            }
        }
    }
    
    if (!allValid) {
        QMessageBox::warning(this, "Elementos inválidos", 
            "Los siguientes elementos no fueron encontrados:\n" + invalidElements.join("\n"));
        return;
    }
    
    // If we get here, all elements are valid - definitive code generated
    // Update UI
    mDocumentID = ui->editCode->text();
oid formBudget::onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)\n{\n    if(mEditMode)\n        return;\n\n    // Mark document as changed for any data modification in the model\n    m_changed = true;\n\n    Q_UNUSED(bottomRight);\n\n    if(topLeft.column() == 1)\n    {\n        qDebug() << topLeft.data().toString();\n        InsertElement(topLeft.data().toString(), topLeft);\n    }\n}

void formBudget::onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
    // Mark document as changed for any data modification in the model\n    m_changed = true;
    if(mEditMode)
        return;
    // Mark document as changed for any data modification in the model\n    m_changed = true;

    Q_UNUSED(bottomRight);

    if(topLeft.column() == 1)
    {
        qDebug() << topLeft.data().toString();
        InsertElement(topLeft.data().toString(), topLeft);
    }
}
void formBudget::insertRow()
{
    ui->treeView->insertRow();
}

void formBudget::insertChild()
{
    ui->treeView->insertChild();
}

void formBudget::removeRow()
{
    ui->treeView->removeRow();
}

void formBudget::focusInEvent(QFocusEvent *event)
{
    qDebug() << "focusInEvent";
}


void formBudget::focusOutEvent(QFocusEvent *event)
{
    qDebug() << "focusOutEvent";
}


void formBudget::on_tabWidget_currentChanged(int index)
{
    if (index == 1)
    {
        ui->ToolbarLines->setVisible(true);
    }
    else
    {
        ui->ToolbarLines->setVisible(false);
    }
}

void formBudget::on_buttonInsertRow_released()
{
    insertRow();
}

void formBudget::on_buttonInsertChild_released()
{
    insertChild();
}

void formBudget::on_buttonRemoveRow_released()
{
    removeRow();
}



void formBudget::insertRowWithType(const QString& type)
{
    insertRow();
    QAbstractItemModel *model = ui->treeView->model();
    int row = model->rowCount() - 1;
    if (row >= 0) {
        model->setData(model->index(row, 13, QModelIndex()), type);
    }
}

void formBudget::on_buttonPercent_released()
{
    insertRowWithType("OT"); // Other
}

void formBudget::on_buttonMaterials_released()
{
    insertRowWithType("MT"); // Material
}

void formBudget::on_buttonMachinery_released()
{
    insertRowWithType("MQ"); // Machinery
}

void formBudget::on_buttonManpower_released()
{
    insertRowWithType("MO"); // ManPower
}

void formBudget::onAnyChange()
{
    m_changed = true;
}

void formBudget::updateMargin()
{
    bool okCost, okPrice;
    double cost = ui->editCost->text().toDouble(&okCost);
    double price = ui->editPrice->text().toDouble(&okPrice);

    if (!okCost || !okPrice || price == 0.0) {
        ui->editProfit->setText("0.00");
        return;
    }

    double margin = (price - cost) / price * 100.0;
    // Block signals to prevent triggering textChanged on editProfit
    const bool block = ui->editProfit->blockSignals(true);
    ui->editProfit->setText(QString::number(margin, 'f', 2));
    ui->editProfit->blockSignals(block);
}