#include "editproductdialog.h"

#include "ui_editproductdialog.h"

#include "../databaseinfo/databaseinfo.h"

#include "../sqltablenoticedelegate/sqltablenoticedelegate.h"

#include "../sqlscript/sqlscript.h"

#include "../integervalidator/integervalidator.h"

#include "../colouredlineedit/colouredlineedit.h"

#include <QSqlRecord>

#include <QDebug>

void EditProductDialog::done(int resultCode) {
  if (resultCode == QDialog::Rejected) {
    QDialog::done(resultCode);
    return;
  }

  int productIdIndex, attributeIdIndex, valueIndex;
  currentRecordInfo(&productIdIndex, &attributeIdIndex, nullptr, &valueIndex);
  for (int row = 0, end = m_model->rowCount(); row != end; ++row) {
    if (m_clearData[row].isNull()) {
      QModelIndex rowIndex = m_model->index(row, valueIndex);
      if (m_model->isDirty(std::move(rowIndex))) {
        int productId = m_model->record(row).value(productIdIndex).toUInt();
        int attributeId =
            m_model->record(row).value(attributeIdIndex).toUInt();
        QVariant value = m_model->record(row).value(valueIndex);
        SqlScript::insertProductValue(productId, attributeId, std::move(value));
      }
    }
  }
  m_model->submitAll();

  auto barcodeText = m_barcodeLineEdit->text();
  if (barcodeText.isEmpty() == false && newBarcodeCorrect == true)
    SqlScript::updateBarcode(m_productId, barcodeText.toLongLong());
  QDialog::done(resultCode);
  return;
}

void EditProductDialog::initializeRecordValues(
    const QSqlRecord &productsJoinProductTypes) {
  CREATE_INDEX(productIdIndex, COLUMN::Products_ProductTypes_ProductId);
  m_productId = productsJoinProductTypes.value(productIdIndex).toUInt();
  CREATE_INDEX(barcodeIndex, COLUMN::Products_ProductTypes_Barcode);
  m_barcode = productsJoinProductTypes.value(barcodeIndex).toLongLong();
  CREATE_INDEX(nameIndex, COLUMN::Products_ProductTypes_ProductName);
  m_name = productsJoinProductTypes.value(nameIndex).toString();
}

void EditProductDialog::createWidgets() {
  m_barcodeLineEdit = new ColouredLineEdit;
  m_ui->m_barcodeLayout->addWidget(m_barcodeLineEdit);
  m_ui->barcodeLabel->setBuddy(m_barcodeLineEdit);
}

void EditProductDialog::configureSqlModel() {
  CREATE_NAME(productId, COLUMN::ProductProperties_ProductId);
  m_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
  m_model->setTable("product_properties");
  m_model->setFilter(QString("[%1] = %2").arg(productId).arg(m_productId));
  m_model->select();

  CREATE_INDEX(valueIndex, COLUMN::ProductProperties_Value);
  int rowCount = m_model->rowCount();
  m_clearData.reserve(rowCount);
  for (int row = 0, end = rowCount; row != end; ++row) {
    QModelIndex valueModelIndex = m_model->index(row, valueIndex);
    QString clearDate = m_model->data(valueModelIndex).toString();
    m_clearData.push_back(clearDate);
  }

  m_ui->m_tableView->setModel(m_model);
  m_ui->m_tableView->setCurrentIndex(QModelIndex());
}

void EditProductDialog::configureWidgets() {
  CREATE_INDEX(productIdIndex, COLUMN::ProductProperties_ProductId);
  m_ui->m_tableView->hideColumn(productIdIndex);
  CREATE_INDEX(attributeIdIndex, COLUMN::ProductProperties_AttributeId);
  m_ui->m_tableView->hideColumn(attributeIdIndex);
  m_ui->m_tableView->horizontalHeader()->setSectionResizeMode(
      QHeaderView::ResizeToContents);
  m_ui->m_tableView->horizontalHeader()->setStretchLastSection(true);

  m_barcodeLineEdit->setMaxLength(13);
  m_barcodeLineEdit->setValidator(new IntegerValidator(m_barcodeLineEdit));
  QString displayedBarcode = QString::number(m_barcode).rightJustified(13, '0');
  m_barcodeLineEdit->setPlaceholderText(displayedBarcode);
}

void EditProductDialog::configureConnections() {
  auto *selectionModel = m_ui->m_tableView->selectionModel();
  connect(selectionModel, &QItemSelectionModel::currentRowChanged, this,
          &EditProductDialog::refreshInputWidgets);
  connect(m_ui->m_modifyProperty, &QPushButton::pressed, this,
          &EditProductDialog::modifyModelValue);
  connect(m_ui->m_modifyBarcode, &QPushButton::pressed, this,
          &EditProductDialog::checkBarcode);
}

void EditProductDialog::configureDisplayedData() {
  bool isEmpty = m_model->rowCount() == 0;
  if (isEmpty ^ m_ui->m_tableView->horizontalHeader()->isHidden())
    m_ui->m_tableView->horizontalHeader()->setHidden(
        /*if table model*/ isEmpty);
  if (isEmpty)
    return;

  CREATE_INDEX(nameIndex, COLUMN::ProductProperties_Name);
  m_model->setHeaderData(nameIndex, Qt::Orientation::Horizontal, tr("Name"));
  CREATE_INDEX(valueIndex, COLUMN::ProductProperties_Value);
  m_model->setHeaderData(valueIndex, Qt::Orientation::Horizontal, tr("Value"));

  setWindowTitle(tr("Editing product \"%1\"").arg(m_name));
}

void EditProductDialog::setEnableProperties(bool enable) {
  m_ui->m_inputWidgets->setEnabled(enable);
  m_ui->m_modifyProperty->setEnabled(enable);
}

void EditProductDialog::refreshInputWidgets(const QModelIndex &currentIndex) {
  bool isValid = currentIndex.isValid();
  setEnableProperties(isValid);

  if (isValid == false)
    return;

  int attributeIdIndex, valueIndex;
  currentRecordInfo(nullptr, &attributeIdIndex, nullptr, &valueIndex);

  QSqlRecord record = m_model->record(currentIndex.row());
  auto value = record.value(valueIndex);

  auto attribute = static_cast<DatabaseInfo::Attribute>(
      record.value(attributeIdIndex).toInt());
  switch (attribute) {
  case DatabaseInfo::Attribute::ArticleNumber:
  case DatabaseInfo::Attribute::Unit:
    m_ui->m_inputWidgets->setCurrentIndex(int(Input::LineEdit));
    m_ui->m_lineEdit->setText(value.toString());
    break;
  case DatabaseInfo::Attribute::DateOfManufacture:
    m_ui->m_inputWidgets->setCurrentIndex(int(Input::DateEdit));
    m_ui->m_dateEdit->setDate(value.toDate());
    break;
  case DatabaseInfo::Attribute::ExpirationDate:
    m_ui->m_inputWidgets->setCurrentIndex(int(Input::SpinBox));
    m_ui->m_spinBox->setValue(value.toInt());
    break;
  default:
    return;
  }
}

void EditProductDialog::modifyModelValue() {
  int attributeIdIndex, nameIndex, valueIndex;
  currentRecordInfo(nullptr, &attributeIdIndex, &nameIndex, &valueIndex);

  int row = m_ui->m_tableView->currentIndex().row();
  QSqlRecord record = m_model->record(row);
  QModelIndex valueModelIndex = m_model->index(row, valueIndex);

  auto attribute = static_cast<DatabaseInfo::Attribute>(
      record.value(attributeIdIndex).toInt());

  switch (attribute) {
  case DatabaseInfo::Attribute::ArticleNumber:
  case DatabaseInfo::Attribute::Unit:
    m_model->setData(valueModelIndex, m_ui->m_lineEdit->text());
    break;
  case DatabaseInfo::Attribute::DateOfManufacture: {
    const QDate &date = m_ui->m_dateEdit->date();
    m_model->setData(valueModelIndex, date.toString(Qt::ISODate));
  } break;
  case DatabaseInfo::Attribute::ExpirationDate:
    m_model->setData(valueModelIndex, m_ui->m_spinBox->text());
  default:
    return;
  }
}

void EditProductDialog::checkBarcode() {
  newBarcodeCorrect = false;
  QString text = m_barcodeLineEdit->text();
  if (text.length() < 13) {
    m_barcodeLineEdit->notice(QColor(0xEEE644), false);
    return;
  }
  bool barcodeExists = SqlScript::doesBarcodeExist(text.toLongLong());
  if (text.length() == 13 && barcodeExists) {
    m_barcodeLineEdit->notice(Qt::red, true);
    return;
  }
  m_barcodeLineEdit->notice(QColor(0xA0EF95), true);
  newBarcodeCorrect = true;
}

void EditProductDialog::currentRecordInfo(int *productIdIndex,
                                          int *attributeIdIndex,
                                          int *nameIndex, int *valueIndex) {
  if (productIdIndex) {
    CREATE_INDEX(value, COLUMN::ProductProperties_ProductId);
    (*productIdIndex) = value;
  }
  if (attributeIdIndex) {
    CREATE_INDEX(value, COLUMN::ProductProperties_AttributeId);
    (*attributeIdIndex) = value;
  }
  if (nameIndex) {
    CREATE_INDEX(value, COLUMN::ProductProperties_Name);
    (*nameIndex) = value;
  }
  if (valueIndex) {
    CREATE_INDEX(value, COLUMN::ProductProperties_Value);
    (*valueIndex) = value;
  }
}

EditProductDialog::EditProductDialog(const QSqlRecord &product, QWidget *parent)
    : QDialog(parent),
      m_model(new QSqlTableModel(this, QSqlDatabase::database())),
      m_ui(new Ui::EditProductDialog) {
  m_ui->setupUi(this);
  setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
  setWindowTitle(tr("Product editing"));
  initializeRecordValues(product);
  configureSqlModel();
  createWidgets();
  configureWidgets();
  configureConnections();
  configureDisplayedData();
  m_ui->m_tableView->setItemDelegate(
      new SqlTableNoticeDelegate(m_ui->m_tableView));
}

EditProductDialog::~EditProductDialog() { delete m_ui; }
