#include <QDebug>
#include <QTimer>

#include <maptool.h>
#include <maplayer.h>
#include <maptoolpan.h>
#include <maptoolselect.h>
#include <maptoolzoomin.h>
#include <maptoolzoomout.h>
#include <maptooldrawline.h>
#include <maptooldrawarea.h>
#include <maptooladdplane.h>
#include "mapautoplane.h"
#pragma execution_character_set("utf-8")

namespace LAMPMainWidget {

PointXY
MapCanvas::defaultMapCenter() {
  return PointXY{116.4074, 39.9042};
}

MapCanvas::MapCanvas(QWidget *parent)
    : QGraphicsView(parent),
      mScene(nullptr),
      mMapExtent(),
      mViewExtent(),
      mDragRect(),
      mIsDragging(false),
      mLayers(),
      mCurrentLayer(nullptr),
      mCrs(nullptr),
      mMapCenter(defaultMapCenter()),
      mZoomValue(kDefaultZoomValue),
      mLastXY(),
      mMapUpdateTimer(nullptr),
      mCurrentTool(nullptr),
      mMapTools() {
  setAutoFillBackground(true);
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  setMouseTracking(true);
  setFocusPolicy(Qt::StrongFocus);
  mScene = new QGraphicsScene();
  setScene(mScene);
  mMapUpdateTimer = new QTimer();
  QObject::connect(mMapUpdateTimer, &QTimer::timeout, [this]() {
    this->mScene->update();
  });
  mMapUpdateTimer->start(200);
  setupTools();
  this->startTimer(1000);
}

MapCanvas::~MapCanvas() {
  mLayers.clear();
  delete mScene;
  delete mCurrentLayer;
  delete mMapUpdateTimer;
}

void
MapCanvas::mousePressEvent(QMouseEvent *event) {
  if (mCurrentTool) {
    mCurrentTool->execute(event);
  }
  QGraphicsView::mousePressEvent(event);
}

void
MapCanvas::mouseReleaseEvent(QMouseEvent *event) {
  if (mCurrentTool) {
    mCurrentTool->execute(event);
  }
  QGraphicsView::mouseReleaseEvent(event);
}

void
MapCanvas::wheelEvent(QWheelEvent *event) {
  int delta = event->angleDelta().y() / 120;
  int zoom = zoomValue();
  zoom += delta;
  setZoomValue(zoom);
}

void
MapCanvas::resizeEvent(QResizeEvent *event) {
    updateViewExtent(true);
}

void MapCanvas::mouseMoveEvent(QMouseEvent *event)
{
    if (mCurrentTool) {
      mCurrentTool->execute(event);
    }
    QGraphicsView::mouseMoveEvent(event);
}

void
MapCanvas::refreshMap() {
  QMapIterator<QString, MapLayer *> iterator(mLayers);
  while (iterator.hasNext()) {
    iterator.next();
    iterator.value()->map()->setViewExtent(mViewExtent);
    iterator.value()->update();
  }
  mScene->update();
}

void
MapCanvas::addLayer(MapLayer *const layer) {
  if (!layer)
    return;

  if (mLayers.contains(layer->id())) {
    qWarning() << layer->id() << "图层已存在";
    return;
  }

  mLayers.insert(layer->id(), layer);
  if (mLayers.count() == 1) {
    setCurrentLayer(layer->id());
  }
  mScene->addItem(layer->map());
  refreshMap();
}

void
MapCanvas::setZoomValue(const int zoom) {
  mZoomValue = normalizeZoom(zoom);
  zoomChanged(mZoomValue);

  /// 更新每个图层的zoom值
  QMapIterator<QString, MapLayer *> iterator(mLayers);
  while (iterator.hasNext()) {
    iterator.next();
    iterator.value()->setZoomValue(mZoomValue);
  }

  /// 更新可视区域的内容
  updateViewExtent(true);
}

void
MapCanvas::updateViewExtent(bool reset) {
  if (!mCurrentLayer) {
    qDebug() << "未设置当前图层，视图区域无法更新";
    return;
  }

  if (reset) {
    /// 重置视图区域
    mScene->setSceneRect(mCurrentLayer->extent());
    QRectF testrect=mCurrentLayer->extent();
    mViewExtent.setRect(0, 0, 0, 0);
    mViewExtent.setSize(size());
    PointXY crsCenter = mCrs->forward(mMapCenter);
    QPointF mapCenter{crsCenter.x() / resolution(), crsCenter.y() / resolution()};
    QPointF offset = mapCenter - mViewExtent.center();
    mViewExtent.translate(offset.x(), offset.y());
  } else {
    /// 视图偏移并重置偏移属性
    mViewExtent.translate(-mDragRect.width(), -mDragRect.height());
    mDragRect.setRect(0, 0, 0, 0);

    /// 更新地图可视区域中心点
    QPointF mapCenter = mViewExtent.center();
    PointXY crsCenter{mapCenter.x() * resolution(), mapCenter.y() * resolution()};
    mMapCenter = mCrs->inverse(crsCenter);
    mapCenterChanged(mMapCenter);
  }

  /// 刷新地图
  centerOn(mViewExtent.center());
  refreshMap();
}

void
MapCanvas::setCrs(const CRS *const crs) {
  mCrs = crs;
  crsChanged();
  updateViewExtent(true);
}

void
MapCanvas::setCurrentLayer(const QString &id) {
  if (!mLayers.contains(id)) {
    qWarning() << "未添加图层=>" << id;
    return;
  }
  mCurrentLayer = mLayers[id];
  if (!mCrs) {
    setCrs(&mCurrentLayer->crs());
  }
  updateViewExtent(true);
}

double
MapCanvas::scale() const {
  return logicalDpiX() * resolution() * 39.37 / 100;;
}

double
MapCanvas::resolution() const {
  if (!mCurrentLayer) {
    qWarning() << "未设置当前图层，无法获取分辨率";
    return 0;
  }

  return mCurrentLayer->resolution();
}

int
MapCanvas::zoomValue() const {
  if (!mCurrentLayer) {
    qWarning() << "未设置当前图层，默认返回zoom值为0";
    return 0;
  }

  return mCurrentLayer->zoomValue();
}

int
MapCanvas::normalizeZoom(const int zoom) const {
  int z{};
  if (zoom <= kMinZoomValue) {
    z = kMinZoomValue;
  } else if (z >= kMaxZoomValue) {
    z = kMaxZoomValue;
  } else {
    z = zoom;
  }

  return z;
}

PointXY
MapCanvas::pixel2Lonlat(const QPointF &point) const {
  QPointF scenePoint = mapToScene(QPoint{static_cast<int>(point.x()), static_cast<int>(point.y())});
  QPointF mapPoint{scenePoint.x() * resolution(), scenePoint.y() * resolution()};
  PointXY crsPoint = mCrs->inverse(PointXY{mapPoint});
  qDebug() << "坐标装换=>{" << point << "=>" << crsPoint << "}";
  return crsPoint;
}

bool
MapCanvas::selectTool(const QString &tool) {
  if (!mMapTools.contains(tool)) {
    qWarning() << QString("%1工具不存在").arg(tool);
    return false;
  }

  auto toolPtr = mMapTools.value(tool);
  if (mCurrentTool) {
    mCurrentTool->deSetup();
  }
  mCurrentTool = toolPtr;
  toolPtr->setup();

  return true;
}

void MapCanvas::timerEvent(QTimerEvent *event)
{
    MapToolAddplane *maptoolAddplane=dynamic_cast<MapToolAddplane*>(mMapTools["addplane_tool"]);
    QList<MapAutoplane*> planes=maptoolAddplane->getPlanes();
    foreach(MapAutoplane *plane,planes){
        plane->updatePos();
    }
}

void
MapCanvas::setupTools() {
  auto panTool = new MapToolPan(this);
  mMapTools.insert(panTool->id(), panTool);

  auto zoominTool = new MapToolZoomIn(this);
  mMapTools.insert(zoominTool->id(), zoominTool);

  auto zoomoutTool = new MapToolZoomOut(this);
  mMapTools.insert(zoomoutTool->id(), zoomoutTool);

  auto selectTool = new MapToolSelect(this);
  mMapTools.insert(selectTool->id(), selectTool);

  auto drawlineTool=new MapToolDrawline(this);
  mMapTools.insert(drawlineTool->id(),drawlineTool);

  auto drawareTool=new MapToolDrawarea(this);
  mMapTools.insert(drawareTool->id(),drawareTool);

  auto addplaneTool=new MapToolAddplane(this);
  mMapTools.insert(addplaneTool->id(),addplaneTool);





}

}
