#include "productdao.h"
#include "../mapplication.h"

bool ProductDAO::create(const QString& code, int type1, int type2, const QString& title,
                      const QString& description, const QString& familyId, const QString& unitId,
                      const QDate& dateUpdate, double realPrice, double discount, double purchasePrice,
                      double benefit, double tax, double salePrice, const QString& barcode,
                      const QByteArray& image, bool state, const QString& manufacturer,
                      const QString& gamma, double weight, double height, double width,
                      double lenght)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("INSERT INTO ELEMENT ("
                "CODE, TYPE1, TYPE2, TITLE, DESCRIPTION, FAMILY_ID, UNIT_ID, "
                "DATE_UPDATE, REAL_PRICE, DISCOUNT, PURCHASE_PRICE, BENEFIT, TAX, SALE_PRICE, "
                "BARCODE, IMAGE, STATE, MANUFACTURER, GAMMA, "
                "WEIGHT, HEIGHT, WIDTH, LENGHT"
                ") VALUES ("
                ":CODE, :TYPE1, :TYPE2, :TITLE, :DESCRIPTION, :FAMILY_ID, :UNIT_ID, "
                ":DATE_UPDATE, :REAL_PRICE, :DISCOUNT, :PURCHASE_PRICE, :BENEFIT, :TAX, :SALE_PRICE, "
                ":BARCODE, :IMAGE, :STATE, :MANUFACTURER, :GAMMA, "
                ":WEIGHT, :HEIGHT, :WIDTH, :LENGHT"
                ");");

    qry.bindValue(":CODE", code);
    qry.bindValue(":TYPE1", type1);
    qry.bindValue(":TYPE2", type2);
    qry.bindValue(":TITLE", title);
    qry.bindValue(":DESCRIPTION", description);
    qry.bindValue(":FAMILY_ID", familyId);
    qry.bindValue(":UNIT_ID", unitId);
    qry.bindValue(":DATE_UPDATE", dateUpdate);
    qry.bindValue(":REAL_PRICE", realPrice);
    qry.bindValue(":DISCOUNT", discount);
    qry.bindValue(":PURCHASE_PRICE", purchasePrice);
    qry.bindValue(":BENEFIT", benefit);
    qry.bindValue(":TAX", tax);
    qry.bindValue(":SALE_PRICE", salePrice);
    qry.bindValue(":BARCODE", barcode);
    qry.bindValue(":IMAGE", image);
    qry.bindValue(":STATE", state);
    qry.bindValue(":MANUFACTURER", manufacturer);
    qry.bindValue(":GAMMA", gamma);
    qry.bindValue(":WEIGHT", weight);
    qry.bindValue(":HEIGHT", height);
    qry.bindValue(":WIDTH", width);
    qry.bindValue(":LENGHT", lenght);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error creating product:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

bool ProductDAO::read(const QString& code, int& type1, int& type2, QString& title,
                    QString& description, QString& familyId, QString& unitId,
                    QDate& dateUpdate, double& realPrice, double& discount, double& purchasePrice,
                    double& benefit, double& tax, double& salePrice, QString& barcode,
                    QByteArray& image, bool& state, QString& manufacturer, QString& gamma,
                    double& weight, double& height, double& width, double& lenght)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("SELECT TYPE1, TYPE2, TITLE, DESCRIPTION, FAMILY_ID, UNIT_ID, "
                "DATE_UPDATE, REAL_PRICE, DISCOUNT, PURCHASE_PRICE, BENEFIT, TAX, SALE_PRICE, "
                "BARCODE, IMAGE, STATE, MANUFACTURER, GAMMA, "
                "WEIGHT, HEIGHT, WIDTH, LENGHT "
                "FROM ELEMENT WHERE CODE = :CODE");
    qry.bindValue(":CODE", code);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error reading product:" << qry.lastError().text();
        dApp->Enterprise().close();
        return false;
    }

    if (qry.next()) {
        type1 = qry.value(0).toInt();
        type2 = qry.value(1).toInt();
        title = qry.value(2).toString();
        description = qry.value(3).toString();
        familyId = qry.value(4).toString();
        unitId = qry.value(5).toString();
        dateUpdate = qry.value(6).toDate();
        realPrice = qry.value(7).toDouble();
        discount = qry.value(8).toDouble();
        purchasePrice = qry.value(9).toDouble();
        benefit = qry.value(10).toDouble();
        tax = qry.value(11).toDouble();
        salePrice = qry.value(12).toDouble();
        barcode = qry.value(13).toString();
        image = qry.value(14).toByteArray();
        state = qry.value(15).toBool();
        manufacturer = qry.value(16).toString();
        gamma = qry.value(17).toString();
        weight = qry.value(18).toDouble();
        height = qry.value(19).toDouble();
        width = qry.value(20).toDouble();
        lenght = qry.value(21).toDouble();
    } else {
        success = false;
    }

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

bool ProductDAO::update(const QString& code, int type1, int type2, const QString& title,
                      const QString& description, const QString& familyId, const QString& unitId,
                      const QDate& dateUpdate, double realPrice, double discount, double purchasePrice,
                      double benefit, double tax, double salePrice, const QString& barcode,
                      const QByteArray& image, bool state, const QString& manufacturer,
                      const QString& gamma, double weight, double height, double width,
                      double lenght)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("UPDATE ELEMENT SET "
                "TYPE1 = :TYPE1, TYPE2 = :TYPE2, TITLE = :TITLE, DESCRIPTION = :DESCRIPTION, FAMILY_ID = :FAMILY_ID, "
                "UNIT_ID = :UNIT_ID, DATE_UPDATE = :DATE_UPDATE, REAL_PRICE = :REAL_PRICE, DISCOUNT = :DISCOUNT, "
                "PURCHASE_PRICE = :PURCHASE_PRICE, BENEFIT = :BENEFIT, TAX = :TAX, SALE_PRICE = :SALE_PRICE, BARCODE = :BARCODE, IMAGE = :IMAGE, "
                "STATE = :STATE, MANUFACTURER = :MANUFACTURER, GAMMA = :GAMMA, WEIGHT = :WEIGHT, HEIGHT = :HEIGHT, "
                "WIDTH = :WIDTH, LENGHT = :LENGHT "\
                "WHERE CODE = :CODE");

    qry.bindValue(":TYPE1", type1);
    qry.bindValue(":TYPE2", type2);
    qry.bindValue(":TITLE", title);
    qry.bindValue(":DESCRIPTION", description);
    qry.bindValue(":FAMILY_ID", familyId);
    qry.bindValue(":UNIT_ID", unitId);
    qry.bindValue(":DATE_UPDATE", dateUpdate);
    qry.bindValue(":REAL_PRICE", realPrice);
    qry.bindValue(":DISCOUNT", discount);
    qry.bindValue(":PURCHASE_PRICE", purchasePrice);
    qry.bindValue(":BENEFIT", benefit);
    qry.bindValue(":TAX", tax);
    qry.bindValue(":SALE_PRICE", salePrice);
    qry.bindValue(":BARCODE", barcode);
    qry.bindValue(":IMAGE", image);
    qry.bindValue(":STATE", state);
    qry.bindValue(":MANUFACTURER", manufacturer);
    qry.bindValue(":GAMMA", gamma);
    qry.bindValue(":WEIGHT", weight);
    qry.bindValue(":HEIGHT", height);
    qry.bindValue(":WIDTH", width);
    qry.bindValue(":LENGHT", lenght);
    qry.bindValue(":CODE", code);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error updating product:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

bool ProductDAO::remove(const QString& code)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("DELETE FROM ELEMENT WHERE CODE = :CODE");
    qry.bindValue(":CODE", code);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error deleting product:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

bool ProductDAO::exists(const QString& code)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("SELECT COUNT(*) FROM ELEMENT WHERE CODE = :CODE");
    qry.bindValue(":CODE", code);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error checking product existence:" << qry.lastError().text();
        dApp->Enterprise().close();
        return false;
    }

    bool exists = false;
    if (qry.next()) {
        exists = (qry.value(0).toInt() > 0);
    }

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

QVector<QString> ProductDAO::getAllCodes()
{
    QVector<QString> codes;
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("SELECT CODE FROM ELEMENT ORDER BY CODE");

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error getting product codes:" << qry.lastError().text();
        dApp->Enterprise().close();
        return codes;
    }

    while (qry.next()) {
        codes.append(qry.value(0).toString());
    }

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

QVector<QPair<QString, double>> ProductDAO::getComposition(const QString& code)
{
    QVector<QPair<QString, double>> composition;
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("SELECT ELEMENT_CODE, ELEMENT_AMOUNT FROM ELEMENTCOMPOSITION WHERE CODE = :CODE");
    qry.bindValue(":CODE", code);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error getting product composition:" << qry.lastError().text();
        dApp->Enterprise().close();
        return composition;
    }

    while (qry.next()) {
        composition.append(qMakePair(qry.value(0).toString(), qry.value(1).toDouble()));
    }

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

bool ProductDAO::addCompositionElement(const QString& productCode, const QString& elementCode, double amount)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("INSERT INTO ELEMENTCOMPOSITION (CODE, ELEMENT_CODE, ELEMENT_AMOUNT) "
                "VALUES (:CODE, :ELEMENT_CODE, :ELEMENT_AMOUNT)");
    qry.bindValue(":CODE", productCode);
    qry.bindValue(":ELEMENT_CODE", elementCode);
    qry.bindValue(":ELEMENT_AMOUNT", amount);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error adding composition element:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

bool ProductDAO::removeCompositionElement(const QString& productCode, const QString& elementCode)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("DELETE FROM ELEMENTCOMPOSITION WHERE CODE = :CODE AND ELEMENT_CODE = :ELEMENT_CODE");
    qry.bindValue(":CODE", productCode);
    qry.bindValue(":ELEMENT_CODE", elementCode);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error removing composition element:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

bool ProductDAO::updateCompositionElement(const QString& productCode, const QString& elementCode, double amount)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("UPDATE ELEMENTCOMPOSITION SET ELEMENT_AMOUNT = :ELEMENT_AMOUNT "
                "WHERE CODE = :CODE AND ELEMENT_CODE = :ELEMENT_CODE");
    qry.bindValue(":ELEMENT_AMOUNT", amount);
    qry.bindValue(":CODE", productCode);
    qry.bindValue(":ELEMENT_CODE", elementCode);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error updating composition element:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

// Remove all composition elements for a product
bool ProductDAO::removeAllComposition(const QString& productCode)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("DELETE FROM ELEMENTCOMPOSITION WHERE CODE = :CODE");
    qry.bindValue(":CODE", productCode);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error removing all composition elements:" << qry.lastError().text();
    }
    dApp->Enterprise().close();
    return success;
}

// Get basic element info (title, unit) for display in composition tree
bool ProductDAO::getElementBasicInfo(const QString& code, QString& title, QString& unitId)
{
    dApp->Enterprise().open();
    QSqlQuery qry = QSqlQuery(dApp->Enterprise());
    qry.prepare("SELECT TITLE, UNIT_ID FROM ELEMENT WHERE CODE = :CODE");
    qry.bindValue(":CODE", code);

    bool success = qry.exec();
    if (!success) {
        qDebug() << "Error getting element basic info:" << qry.lastError().text();
        dApp->Enterprise().close();
        return false;
    }

    if (qry.next()) {
        title = qry.value(0).toString();
        unitId = qry.value(1).toString();
    } else {
        success = false;
    }

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