#include "main_window.h"
#include "ui_main_window.h"

#include <QFileDialog>
#include <QImage>
#include <QResource>

static const char *CalligrapherAbbrMap[] = {
    "wxz",
    "yzq",
    "lgq",
    "sgt",
    "smh",
    "mf",
    "htj",
    "oyx",
    "zmf",
    "csl",
    "wzm",
    "lqs",
    "yyr",
    "hy",
    "bdsr",
    "fwq",
    "gj",
    "shz",
    "mzd",
    "lx",
};

MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}, mUi{new Ui::MainWindow}, mAboutDialog{this}, mErrorReport{this} {

  QResource::registerResource("resource.rcc");

  mUi->setupUi(this);

  mDocument.setDefaultFont(QFont{"Microsoft Yahei", 11});
  mUi->viewCalligrapherInfo->setDocument(&mDocument);

  mErrorReport.setWindowTitle("ERROR");
  mErrorReport.setModal(true);

  connect(mUi->btnBack, &QPushButton::clicked, this, &MainWindow::onCalligrapherBack);
  connect(mUi->btnFront, &QPushButton::clicked, this, &MainWindow::onCalligrapherFront);
  connect(mUi->btnAbout, &QPushButton::clicked, this, &MainWindow::onAbout);
  connect(mUi->btnSelectInput, &QPushButton::clicked, this, &MainWindow::onSelectInput);
  connect(mUi->btnConfirm, &QPushButton::clicked, this, &MainWindow::onConfirm);
  connect(mUi->btnReset, &QPushButton::clicked, this, &MainWindow::onReset);
}

MainWindow::~MainWindow() {
  delete mUi;
}

void MainWindow::ensureCalligraphyProcess() {
  if (!mCalligraphyProcess) {
    try {
      mCalligraphyProcess = std::make_unique<CalligraphyProcess>();
    } catch (const std::exception &e) {
      reportError(e.what());
      throw;
    }
  }
}

void MainWindow::onCalligrapherBack() {
  if (mCurrentCalligrapher >= 0)
    updateCalligraphers(mCurrentCalligrapher - 1);
}

void MainWindow::onCalligrapherFront() {
  if (mCurrentCalligrapher >= 0)
    updateCalligraphers(mCurrentCalligrapher + 1);
}

void MainWindow::onSelectInput() {
  QFileDialog dialog{this};
  dialog.setModal(true);
  dialog.setNameFilter(tr("Images (*.bmp *.gif *.jpg *.jpeg *.png *.pbm *.pgm *.ppm *.xbm *.xpm)"));

  if (dialog.exec()) {
    mCalligraphyImage.load(dialog.selectedFiles().first());
    setCalligraphyImage(mCalligraphyImage);
    updateCalligraphers(-1);
  }
}

void MainWindow::onConfirm() {
  if (!mCalligraphyImage.isNull()) {
    ensureCalligraphyProcess();
    mCalligraphyProcess->findCalligraphers(mCalligraphyImage, mCalligraphyImageWithBoxes, mCalligrapherIndices);

    setCalligraphyImage(mCalligraphyImageWithBoxes);
    updateCalligraphers(0);
  }
}

void MainWindow::onReset() {
  mCalligraphyImage = QImage{};
  mCalligraphyImageWithBoxes = QImage{};

  setCalligraphyImage(mCalligraphyImage);

  mCalligrapherIndices.clear();
  updateCalligraphers(-1);
}

void MainWindow::onAbout() {
  mAboutDialog.exec();
}

void MainWindow::setCalligraphyImage(const QImage &image) {
  QPixmap pixmap = QPixmap::fromImage(image);
  QSize viewSize = mUi->viewlnputImage->size();
  mUi->viewlnputImage->setPixmap(pixmap.scaled(viewSize, Qt::KeepAspectRatio));
}

void MainWindow::updateCalligraphers(int idx) {
  idx = std::clamp<int>(idx, -1, mCalligrapherIndices.size() - 1);
  mCurrentCalligrapher = idx;

  if (idx == -1) {
    mDocument.clear();
    mUi->viewCurrentTotal->setText("");
    return;
  }

  if (mCalligrapherIndices.size() == 0) {
    mDocument.clear();
    mUi->viewCurrentTotal->setText("0/0");
    return;
  }

  int indice = mCalligrapherIndices[idx];
  if (indice >= 0 && indice < std::size(CalligrapherAbbrMap)) {
    QString url = QString(":/static/%1.html").arg(CalligrapherAbbrMap[indice]);
    QResource html{url};
    mDocument.setHtml(reinterpret_cast<const char *>(html.data()));

    QString text = QString("%1/%2").arg(idx + 1).arg(mCalligrapherIndices.size());
    mUi->viewCurrentTotal->setText(text);
  }
}

void MainWindow::reportError(const QString &msg) {
  mErrorReport.setText(msg);
  mErrorReport.exec();
}
