/**
 * @file RasterProjectBase.cpp
 * @brief None
 * @author 陈增辉 (3045316072@qq.com)
 * @version 2.5.0
 * @date 24-6-4
 * @copyright Copyright (c) Since 2024 中科卫星应用研究院  All rights reserved.
 */

#include <QDebug>
#include "RasterToolBase.h"
#include "gdal_priv.h"
#include "ogr_spatialref.h"
#include "cpl_conv.h" // for CPLMalloc()
#include <QTextCodec>
#include <iostream>
#include <QFile>

namespace RasterToolBase {
	long getProjectEPSGCodeByLon_Lat(double lon, double lat, ProjectStripDelta stripState)
	{
		long EPSGCode = 0;
		switch(stripState) {
			case ProjectStripDelta::Strip_3: {
				break;
			};
			case ProjectStripDelta::Strip_6: {
				break;
			}
			default: {
				EPSGCode = -1;
				break;
			}
		}
		qDebug() << QString(" EPSG code : %1").arg(EPSGCode);
		return EPSGCode;
	}
	long getProjectEPSGCodeByLon_Lat_inStrip3(double lon, double lat)
	{
		// EPSG 4534 ~ 4554 3 度带
		// 首先判断是否是在 中国带宽范围
		// 中心经度范围 ：75E ~ 135E 实际范围 73.5E ~ 136.5E,
		// 纬度范围 3N ~ 54N，放宽到 0N~ 60N
		if(73.5 <= lon && lon <= 136.5 && 0 <= lat && lat <= 60) { // 中国境内
			long code = trunc((lon - 73.5) / 3) + 4534;
			return code;
		} else { // 非中国境内 使用 高斯克吕格
			bool isSouth = lat < 0; // 简单判断南北半球，这里仅为示例，实际应用可能需要更细致的逻辑
			long prefix = isSouth ? 327000 : 326000;
			// std::string prefix = isSouth ? "327" : "326";
			lon			  = fmod(lon + 360.0, 360.0);
			long zone	  = std::floor((lon + 180.0) / 3.0);
			prefix		  = prefix + zone;
			return prefix;
		}
		return 0;
	}
	long getProjectEPSGCodeByLon_Lat_inStrip6(double lon, double lat)
	{
		// EPSG 4502 ~ 4512   6度带
		// 首先判断是否是在 中国带宽范围
		// 中心经度范围 ：75E ~ 135E 实际范围 72.0E ~ 138E,
		// 纬度范围 3N ~ 54N，放宽到 0N~ 60N
		if(73.5 <= lon && lon <= 136.5 && 0 <= lat && lat <= 60) { // 中国境内
			long code = trunc((lon - 72.0) / 6) + 4502;
			return code;
		} else { // 非中国境内 使用 UTM// 确定带号，6度带从1开始到60，每6度一个带
			int	   zone			= static_cast<int>((lon + 180.0) / 6.0) + 1;
			bool   isSouth		= lon < 0;				   // 判断是否在南半球
			long epsgCodeBase = isSouth ? 32700 : 32600; // 计算EPSG代码
			long prefix		= static_cast<int>(epsgCodeBase + zone);
			return prefix;
		}
		return 0;
	}

	QString GetProjectionNameFromEPSG(long epsgCode)
	{
		qDebug() << "============= GetProjectionNameFromEPSG ======================";
		OGRSpatialReference oSRS;

		// 设置EPSG代码
		if(oSRS.importFromEPSG(epsgCode) != OGRERR_NONE) {
			qDebug() << "epsgcode not  recognition";
			return "";
		}

		// 获取并输出坐标系的描述（名称）
		const char* pszName = oSRS.GetAttrValue("GEOGCS");
		if(pszName) {
			qDebug() << "Coordinate system name for EPSG " + QString::number(epsgCode)
					 << " is: " + QString::fromStdString(pszName);
			return QString::fromStdString(pszName);
		} else {
			qDebug() << "Unable to retrieve the name for EPSG " + QString::number(epsgCode);
			return "";
		}

		//		char*				wkt = NULL;
		//		// 转换为WKT格式
		//		oSRS.exportToWkt(&wkt);
		//
		//		qDebug() << wkt;
		//
		//		// 从WKT中解析投影名称，这里简化处理，实际可能需要更复杂的逻辑来准确提取名称
		//		std::string wktStr(wkt);
		//		long start = wktStr.find("PROJCS[\"") + 8; // 找到"PROJCS["后的第一个双引号位置
		//		// 从start位置开始找下一个双引号，这之间的内容即为投影名称
		//		int	end		 = wktStr.find('\"', start);
		//		QString projName = QString::fromStdString(wktStr.substr(start, end - start));
		//
		//		// 释放WKT字符串内存
		//		CPLFree(wkt);

		// return projName;
	}
	long GetEPSGFromRasterFile(QString filepath)
	{
		qDebug() << "============= GetEPSGFromRasterFile ======================";
		//		QTextCodec* codec = QTextCodec::codecForLocale(); // 获取系统默认编码的文本编解码器
		//		QByteArray	byteArray = codec->fromUnicode(filepath); // 将QString转换为QByteArray
		//,这个应该会自动释放 		const char* charArray = byteArray.constData(); //
		// 获取QByteArray的const char*指针

		{
			if(QFile(filepath).exists()){
				qDebug() << "info: the image found.\n";
			}else{
				return -1;
			}

			GDALAllRegister();
			CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注册GDAL驱动
			//			qDebug()<<filepath.toLocal8Bit().constData()<<std::endl;
			// 打开影像文件
			GDALDataset* poDataset;
			poDataset = (GDALDataset*)GDALOpen(filepath.toUtf8().data(), GA_ReadOnly);
			if(NULL==poDataset) {
				qDebug() << "Error: Unable to open the image.\n";
				return -1;
			}

			// 获取影像的投影信息
			const char* pszProjection = poDataset->GetProjectionRef();

			qDebug() << QString::fromUtf8(pszProjection);

			// 创建SpatialReference对象
			OGRSpatialReference oSRS;
			if(oSRS.importFromWkt((char**)&pszProjection) != OGRERR_NONE) {
				qDebug() << ("Error: Unable to import projection information.\n");
				GDALClose(poDataset);
				return -1;
			}

			long epsgCode = atoi(oSRS.GetAuthorityCode(nullptr)); // 获取EPSG代码

			if(epsgCode != 0) {
				GDALClose(poDataset);
				qDebug() << QString("file %1 :epsg Code %2").arg(filepath).arg(epsgCode);
				return epsgCode;
			} else {
				qDebug() << "EPSG code could not be determined from the spatial reference.";
				GDALClose(poDataset);
				return -1;
			}
		}
	}
	std::shared_ptr<PointRaster> GetCenterPointInRaster(QString filepath)
	{
		qDebug() << "============= GetCenterPointInRaster ======================";
		//		QTextCodec* codec = QTextCodec::codecForLocale(); // 获取系统默认编码的文本编解码器
		//		QByteArray	byteArray = codec->fromUnicode(filepath); // 将QString转换为QByteArray
		//,这个应该会自动释放 		const char* charArray = byteArray.constData(); //
		// 获取QByteArray的const char*指针
		GDALAllRegister();
		CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
		CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
		// qDebug()<<filepath.toLocal8Bit().constData()<<std::endl;
		GDALDataset* poDataset = (GDALDataset*)GDALOpen(filepath.toUtf8().data(), GA_ReadOnly);
		if(nullptr==poDataset||NULL==poDataset) {
			qDebug() << "Could not open dataset";
			return nullptr; // 表示读取失败
		}

		double x, y, z;

		bool   flag = false;

		{
			double adfGeoTransform[6];
			if(poDataset->GetGeoTransform(adfGeoTransform) != CE_None) {
				qDebug() << "Failed to get GeoTransform";
				return nullptr;
			}

			double dfWidth	 = poDataset->GetRasterXSize();
			double dfHeight	 = poDataset->GetRasterYSize();

			// 计算中心点坐标（像素坐标）
			double dfCenterX = adfGeoTransform[0] + dfWidth * adfGeoTransform[1] / 2.0
							 + dfHeight * adfGeoTransform[2] / 2.0;
			double dfCenterY = adfGeoTransform[3] + dfWidth * adfGeoTransform[4] / 2.0
							 + dfHeight * adfGeoTransform[5] / 2.0;

			OGRSpatialReference oSRS;
			oSRS.importFromWkt(poDataset->GetProjectionRef());

			if(oSRS.IsGeographic()) {
				qDebug() << "Center coords (already in geographic): (" + QString::number(dfCenterX)
								+ ", " + QString::number(dfCenterY) + ")";
				flag = true;
				x	 = dfCenterX;
				y	 = dfCenterY;
			} else {
				// 如果不是地理坐标系，转换到WGS84
				OGRSpatialReference oSRS_WGS84;
				oSRS_WGS84.SetWellKnownGeogCS("WGS84");

				OGRCoordinateTransformation* poCT =
					OGRCreateCoordinateTransformation(&oSRS, &oSRS_WGS84);
				if(poCT == nullptr) {
					qDebug() << "Failed to create coordinate transformation";
					return nullptr;
				}

				// double dfLon, dfLat;
				if(poCT->Transform(1, &dfCenterX, &dfCenterY)) {
					qDebug() << "Center coords (transformed to WGS84): ("
									+ QString::number(dfCenterX) + ", " + QString::number(dfCenterY)
							 << ")";
					flag = true;
					x	 = dfCenterX;
					y	 = dfCenterY;
				} else {
					qDebug() << "Transformation failed.";
				}
				OGRCoordinateTransformation::DestroyCT(poCT);
			}
		}
		if(nullptr==poDataset||NULL==poDataset){}else{
			GDALClose(poDataset);
		}

		if(flag) {
			std::shared_ptr<PointRaster> RasterCenterPoint = std::make_shared<PointRaster>();
			RasterCenterPoint->x						   = x;
			RasterCenterPoint->y						   = y;
			RasterCenterPoint->z						   = 0;
			return RasterCenterPoint;
		} else {
			return nullptr;
		}
	}
	CoordinateSystemType getCoordinateSystemTypeByEPSGCode(long epsg_code)
	{
		OGRSpatialReference oSRS;
		if(oSRS.importFromEPSG(epsg_code) == OGRERR_NONE) {
			if(oSRS.IsGeographic()) {
				return CoordinateSystemType::GeoCoordinateSystem;
			} else if(oSRS.IsProjected()) {
				return CoordinateSystemType::ProjectCoordinateSystem;
			}
		} else {
			return CoordinateSystemType::UNKNOW;
		}
	}
} // namespace RasterToolBase