/* BEGIN software license
 *
 * MsXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright 2009--2026 by Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the MsXpertSuite project.
 *
 * The MsXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


/////////////////////// StdLib includes


/////////////////////// Qt includes
#include <QDebug>
#include <QAction>
#include <QKeySequence>
#include <QSettings>
#include <QCryptographicHash>


/////////////////////// pappsomspp includes


/////////////////////// libXpertMassCore includes


/////////////////////// Local includes
#include "MsXpS/libXpertMassGui/WindowGeometryManager.hpp"

namespace MsXpS
{

namespace libXpertMassGui
{


QString
WindowGeometryManager::setupId()
{
  static QString id;
  if(id.isEmpty())
    {
      QList<QPair<QPoint, QString>> screen_infos;

      for(QScreen *screen : QGuiApplication::screens())
        {
          if(!screen)
            continue;

          QRect geo = screen->geometry();

          QString info =
            QString("%1;%2x%3@%4,%5;%6")
              .arg(screen->name().isEmpty() ? screen->objectName()
                                            : screen->name())
              .arg(geo.width())
              .arg(geo.height())
              .arg(geo.x())
              .arg(geo.y())
              .arg(screen == QGuiApplication::primaryScreen() ? 'P' : 'S');

          qDebug() << "One monitor setup in extenso:" << info;

          screen_infos << qMakePair(geo.topLeft(), info);
        }
      std::sort(screen_infos.begin(),
                screen_infos.end(),
                [](const auto &a, const auto &b) {
                  return a.first != b.first ? a.first.x() < b.first.x()
                                            : a.first.y() < b.first.y();
                });

      QStringList sorted;

      for(const auto &p : screen_infos)
        sorted << p.second;
      id = QCryptographicHash::hash(sorted.join("|").toUtf8(),
                                    QCryptographicHash::Sha1)
             .toHex();
    }
  return id;
}

void
WindowGeometryManager::save(const QWidget *widget,
                            const QString &key,
                            QSettings &settings)
{
  if(!widget)
    return;
  QString group = QString("WorkspaceGeometries/%1/%2").arg(setupId(), key);
  settings.beginGroup(group);
  settings.setValue("geometry", widget->saveGeometry());
  settings.setValue("windowState", static_cast<int>(widget->windowState()));
  settings.endGroup();
}

void
WindowGeometryManager::restore(QWidget *widget,
                               const QString &key,
                               QSettings &settings)
{
  if(!widget)
    return;

  QString group = QString("WorkspaceGeometries/%1/%2").arg(setupId(), key);
  if(!settings.contains(group + "/geometry"))
    return;

  settings.beginGroup(group);
  widget->restoreGeometry(settings.value("geometry").toByteArray());

  Qt::WindowStates state =
    static_cast<Qt::WindowStates>(settings.value("windowState").toInt());

  // Never restore minimized directly; it breaks show() on some platforms

  widget->setWindowState(state & ~Qt::WindowMinimized);
  settings.endGroup();

  // If the restored window is off-screen, make it appear !
  ensureWindowIsVisible(widget);
}

void
WindowGeometryManager::ensureWindowIsVisible(QWidget *widget)
{
  if(!widget)
    return;

  // Skip validation for maximized/fullscreen: the WM will handle placement
  if(widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
    return;

  QRect frame  = widget->frameGeometry();
  bool visible = false;
  for(QScreen *screen : QGuiApplication::screens())
    {
      if(screen->availableGeometry().intersects(frame))
        {
          visible = true;
          break;
        }
    }

  if(!visible)
    {
      QScreen *primary = QGuiApplication::primaryScreen();
      QRect avail      = primary->availableGeometry();

      // ✅ Correct, type-safe centering
      frame.moveCenter(avail.center());
      widget->move(frame.topLeft());
    }
}


} // namespace libXpertMassGui

} // namespace MsXpS
