"""
/***************************************************************************
 MakeFloodMapDialog
                                 A QGIS plugin
 flood map maker plugin
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2022-02-16
        git sha              : $Format:%H$
        copyright            : (C) 2022 by KICT, Hermesys
        email                :  
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import math
import os

from qgis import processing
from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry
from qgis.core import QgsField, QgsProject, QgsRasterLayer
from qgis.PyQt.QtCore import QVariant


class MakeFloodMap:
    def __init__(self):
        self.project = QgsProject.instance()

    def runTin(self, line, dem, csv, exType, output):
        # Project에서 사용자 정의 좌표계 추가 및 측선 레이어 좌표계 변경 (이상한 값 생성 방지)
        demLayer = QgsRasterLayer(dem, "DEM Layer", "gdal")
        demCrs = demLayer.crs()
        if not demCrs.authid():
            demCrs.saveAsUserCrs("Make flood map user defined crs")

        params = {"INPUT": line, "OUTPUT": "TEMPORARY_OUTPUT", "TARGET_CRS": demCrs}
        clnTgLayer = processing.run("native:reprojectlayer", params)["OUTPUT"]
        self.project.addMapLayer(clnTgLayer, False)

        extent = clnTgLayer.extent()
        if exType == "buffer":
            extent = extent.buffered(100)
        elif exType == "dem":
            extent = demLayer.extent()

        cellSize, extTxt = self.calcExtent(demLayer, extent)

        # CSV와 Join해서 필드 생성하기
        if os.path.isfile(csv):
            self.addDepthColumn(clnTgLayer, csv)

        tgFieldNo = clnTgLayer.attributeList()[-1]
        params = {
            "EXTENT": extTxt,
            "INTERPOLATION_DATA": clnTgLayer.source() + f"::~::0::~::{tgFieldNo}::~::1",
            "METHOD": 0,
            "OUTPUT": output,
            "PIXEL_SIZE": cellSize,
        }
        rstPath = processing.run("qgis:tininterpolation", params)["OUTPUT"]
        name = os.path.basename(rstPath)[:-4]
        rstLayer = QgsRasterLayer(rstPath, name, "gdal")

        #         self.project.addMapLayer(rstLayer)
        self.project.removeMapLayer(clnTgLayer)
        return rstLayer

    def calcExtent(self, demLry, tgExt):
        cellSize = demLry.rasterUnitsPerPixelX()
        demExt = demLry.extent()

        xmin = self.getCalcExtent(demExt.xMinimum(), tgExt.xMinimum(), cellSize, "min")
        ymin = self.getCalcExtent(demExt.yMinimum(), tgExt.yMinimum(), cellSize, "min")
        xmax = self.getCalcExtent(demExt.xMaximum(), tgExt.xMaximum(), cellSize, "max")
        ymax = self.getCalcExtent(demExt.yMaximum(), tgExt.yMaximum(), cellSize, "max")

        extentText = f"{xmin},{xmax},{ymin},{ymax} [{demLry.crs().authid()}]"
        return cellSize, extentText

    def getCalcExtent(self, d, t, cs, tp):  # dem, target, cellseize, type
        calc = math.floor if tp == "min" else math.ceil
        rst = d + cs * calc((t - d) / cs)
        return rst

    def addDepthColumn(self, layer, csv):
        layer.startEditing()
        layer.addAttribute(QgsField("elevation", QVariant.Double))
        features = layer.getFeatures()
        noIndex = layer.fields().lookupField("no")

        with open(csv, "r", encoding="utf-8") as f:
            for line in f.readlines():
                no, wl = line.strip().split(",")

                for i, fea in enumerate(features):
                    attb = fea.attributes()
                    if str(attb[noIndex]).strip() == str(no).strip():
                        fea.setAttribute(len(attb) - 1, QVariant(wl))
                        layer.updateFeature(fea)
                        break

            layer.commitChanges()

    def runCalcDepth(self, targetLayer, dem, savePath):
        demLayer = QgsRasterLayer(dem, "DEM Layer", "gdal")
        demName = demLayer.name() + "_rasterCalc@1"
        targetName = targetLayer.name() + "_rasterCalc@2"
        calc = (
            f'(("{targetName}">"{demName}")*"{targetName}"-"{demName}")'
            + f'/ (("{targetName}">"{demName}")*1 + ("{targetName}"<="{demName}")*0)'
        )

        rasTgt = QgsRasterCalculatorEntry()
        rasTgt.ref = targetName
        rasTgt.raster = targetLayer
        rasTgt.bandNumber = 1  # 다중 밴드 사진일 때 밴드 순서 호출

        rasDem = QgsRasterCalculatorEntry()
        rasDem.ref = demName
        rasDem.raster = demLayer
        rasDem.bandNumber = 1  # 다중 밴드 사진일 때 밴드 순

        entries = [rasTgt, rasDem]
        result = QgsRasterCalculator(
            calc,
            savePath,
            "GTiff",
            targetLayer.extent(),
            targetLayer.width(),
            targetLayer.height(),
            entries,
        )

        if result.processCalculation() != 0:
            print("error")

        name = os.path.basename(savePath)[:-4]
        layer = QgsRasterLayer(savePath, name, "gdal")
        #         self.project.addMapLayer(layer)
        return layer
