# -*- coding: utf-8 -*-

__author__ = '(C) 2023 by Gerald Kogler'
__date__ = '1/10/2023'
__copyright__ = 'Copyright 2023, 300.000 Km/s'
__license__ = 'GPLv3 license'

import os
import processing
import shutil
import json
from .mapboxStyleScripts import getLayerStyle
from functools import partial

from qgis.PyQt import uic
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt import QtWidgets
from qgis.PyQt.QtWidgets import QLineEdit, QComboBox, QPlainTextEdit, QCheckBox, QSpinBox, QTableWidgetItem, QPushButton, QListWidgetItem, QDialogButtonBox, QProgressBar, QToolButton, QAction, QMenu, QDialog, QVBoxLayout, QDialogButtonBox, QLabel
from qgis.PyQt.QtCore import *

from qgis.gui import QgsFileWidget, QgsMapLayerComboBox
from qgis.core import QgsProject, Qgis, QgsTaskManager, QgsMessageLog, QgsProcessingAlgRunnerTask, QgsApplication, QgsProcessingContext, QgsProcessingFeedback, QgsVectorFileWriter, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsRectangle, QgsMapSettings, QgsProcessing

from .qwv_dialog11 import QWVDialog11
from .utils import Utils

FORM_CLASS, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'qwv_dialog1_base.ui'))

MINZOOM = 8
MAXZOOM = 15
MINZOOM_ALLOWED = 1
MAXZOOM_ALLOWED = 18

class QWVDialog1(QtWidgets.QDialog, FORM_CLASS):

    def __init__(self, iface, parent=None, _printLog=None):
        """Constructor."""
        super(QWVDialog1, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect

        self.iface = iface
        self.setupUi(self)
        self._printLog = _printLog

        # list for references in views table
        self.dialog1_views.layers = []
        self.dialog1_views.btns = []

        self.buildUi()


    def buildUi(self):
        """Fill lists and build UI."""

        # add buttons
        self.runBtn = QPushButton(Utils.getIcon("system-run"), Utils.tr("Run"))
        self.button_box.addButton(self.runBtn, QDialogButtonBox.ApplyRole)

        self.saveBtn = QPushButton(Utils.getIcon("document-save"), Utils.tr("Save Settings"))
        self.button_box.addButton(self.saveBtn, QDialogButtonBox.ActionRole)

        self.closeBtn = QPushButton(Utils.getIcon("window-close"), Utils.tr("Close"))
        self.button_box.addButton(self.closeBtn, QDialogButtonBox.ActionRole)

        self.helpBtn = QPushButton(Utils.getIcon("help"), Utils.tr("Help"))
        self.button_box.addButton(self.helpBtn, QDialogButtonBox.HelpRole)

        # bgLayersFile = os.path.join(os.path.dirname(__file__), "resources/bg_layers.json")
        # with open(bgLayersFile) as json_data:
        #     bgLayers = json.load(json_data)

        # for bgLayer in bgLayers:
        #     osmItem = QListWidgetItem(Utils.tr(bgLayer["name"]))
        #     osmItem.setData(Qt.UserRole, bgLayer["source"])
        #     self.dialog1_backgrounds.addItem(osmItem)

        # prepare Background list
        # osmItem = QListWidgetItem(Utils.tr('OpenStreetMap VT simple'))
        # osmItem.setToolTip('https://resources.quickwebviewer.org/osm/osm_low/{z}/{x}/{y}.pbf')
        # osmItem.setData(Qt.UserRole, {"type": "vector", "style": "https://resources.quickwebviewer.org/styles/osm_low.json", "lowestLayer": "t_2"})
        # self.dialog1_backgrounds.addItem(osmItem)

        # osmItem = QListWidgetItem(Utils.tr('OpenStreetMap'))
        # osmItem.setToolTip('https://a.tile.openstreetmap.org/{z}/{x}/{y}.png')
        # osmItem.setData(Qt.UserRole, {"type": "raster", "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], "tileSize": 256, "attribution": "&copy; OpenStreetMap Contributors", "maxzoom": 19})
        # self.dialog1_backgrounds.addItem(osmItem)

        # satelliteItem = QListWidgetItem(Utils.tr('Satellite'))
        # satelliteItem.setToolTip('https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-2020_3857/default/g/{z}/{y}/{x}.png')
        # satelliteItem.setData(Qt.UserRole, {"type": "raster", "tiles": ["https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-2020_3857/default/g/{z}/{y}/{x}.png"], "tileSize": 256, "attribution": "&copy; Sentinel-2 cloudless 2022 by EOX IT Services GmbH", "maxzoom": 19})
        # self.dialog1_backgrounds.addItem(satelliteItem)

        # prepare Attachment table
        self.addRowAttachment()
        self.dialog1_addfile.clicked.connect(self.addRowAttachment)
        self.dialog1_removefile.clicked.connect(self.removeRowAttachment)

        # prepare extent selector
        self.setMapCanvasExtent()
        extentIcon = Utils.getIcon("pointer")
        extentAction = QAction(extentIcon, Utils.tr("Use Current Map Canvas Extent"), self)
        extentAction.triggered.connect(self.setMapCanvasExtent)
        self.dialog1_extent_menu.setDefaultAction(extentAction)
        self.dialog1_extent_menu.addAction(extentAction)

        extentActionView = QAction(Utils.tr("Use Project Extent"), self)
        self.dialog1_extent_menu.addAction(extentActionView)
        extentActionView.triggered.connect(lambda:self.setViewExtent(extentAction))

        # extentActionLayer = QAction(Utils.tr("Calculate From Layer"), self)
        # extentActionLayerMenu = QMenu()
        # extentActionLayer.setMenu(extentActionLayerMenu)
        # # add all layers
        # for k, layer in QgsProject.instance().mapLayers().items():
        #     extentActionLayerMenu.addMenu(QMenu(layer.name()))
        # self.dialog1_extent_menu.addAction(extentActionLayer)
        
        # prepare Views table
        #self.addRowView()
        self.dialog1_addview.clicked.connect(self.addRowView)
        self.dialog1_removeview.clicked.connect(lambda:self.removeRowView(self.getSelectedViewRow()))

        self.dlg11 = QWVDialog11(self.iface, self)
        self.dlg11.closeBtn.clicked.connect(lambda:self.dlg11.hide())
        self.dlg11.saveBtn.clicked.connect(lambda:self.dlg11.saveData(self.getSelectedViewRow()))


    def setMapCanvasExtent(self):
        """Set extent field to current map canvas extent."""

        extent = Utils.getExtentFormatted(self.iface.mapCanvas().extent(), self.iface.mapCanvas().mapSettings().destinationCrs().authid())
        self.dialog1_extent.setText(extent)


    def setViewExtent(self, extentAction):
        """Set extent field to project extent."""

        projectExtent = QgsRectangle(0,0,0,0)
        for k, layer in QgsProject.instance().mapLayers().items():
            projectExtent.combineExtentWith(QgsProject.instance().mapLayer(layer.id()).extent())

        extent = Utils.getExtentFormatted(projectExtent, self.iface.mapCanvas().mapSettings().destinationCrs().authid())
        self.dialog1_extent.setText(extent)

        # always set map extent as default action
        self.dialog1_extent_menu.setDefaultAction(extentAction)


    def addRowAttachment(self, file=None, name=None):
        """Add row to attachment table."""

        index = self.dialog1_attachments.rowCount()
        self.dialog1_attachments.insertRow(index)

        dialog1_attachments_file = QgsFileWidget()
        try:
            dialog1_attachments_file.setStorageMode(QgsFileWidget.StorageMode.GetFile)
        except:
            print("setStorageMode not available for this QGIS version")
        if file:
            dialog1_attachments_file.setFilePath(file)
        self.dialog1_attachments.setCellWidget(index, 0, dialog1_attachments_file)

        dialog1_attachments_name = QLineEdit()
        if name:
            dialog1_attachments_name.setText(name)
        self.dialog1_attachments.setCellWidget(index, 1, dialog1_attachments_name)


    def removeRowAttachment(self):
        """Remove row from attachment table."""

        selectedRows = self.dialog1_attachments.selectionModel().selectedRows()

        if len(selectedRows) > 0:
            self.dialog1_attachments.removeRow(selectedRows[0].row())


    def addRowView(self, viewId=None, name=None, description=None, layers=None, zoommin=None, zoommax=None):
        """Add row to view table."""

        # print("addRowView", viewId, name, description, layers, zoommin, zoommax)

        index = self.dialog1_views.rowCount()
        self.dialog1_views.insertRow(index)
        self.dialog1_views.layers.append(None)

        # view
        dialog1_views_view = QComboBox()
        dialog1_views_view.addItems(self.getViewList())
        if viewId:
            dialog1_views_view.setCurrentText(viewId)
        dialog1_views_view.currentIndexChanged.connect(lambda:self.setViewName(dialog1_views_view.currentText()))
        self.dialog1_views.setCellWidget(index, 0, dialog1_views_view)

        # name
        dialog1_views_name = QLineEdit()
        if name:
            dialog1_views_name.setText(name)
        self.dialog1_views.setCellWidget(index, 1, dialog1_views_name)

        # description
        dialog1_views_description = QPlainTextEdit()
        if description:
            dialog1_views_description.appendPlainText(description)
        self.dialog1_views.setCellWidget(index, 2, dialog1_views_description)

        # layers
        editBtn = QPushButton(Utils.tr("Edit"))
        editBtn.clicked.connect(lambda:self.showLayersDialog(index))
        self.dialog1_views.btns.append(editBtn)
        self.dialog1_views.setCellWidget(index, 3, editBtn)
        if layers:
            self.dialog1_views.layers[index] = layers

        # zoommin
        dialog1_views_zoommin = QSpinBox()
        dialog1_views_zoommin.setMinimum(MINZOOM_ALLOWED)
        dialog1_views_zoommin.setMaximum(MAXZOOM_ALLOWED)
        if zoommin:
            dialog1_views_zoommin.setValue(zoommin)
        else:
            dialog1_views_zoommin.setValue(MINZOOM)
        self.dialog1_views.setCellWidget(index, 4, dialog1_views_zoommin)

        # zoommax
        dialog1_views_zoommax = QSpinBox()
        dialog1_views_zoommax.setMinimum(MINZOOM_ALLOWED)
        dialog1_views_zoommax.setMaximum(MAXZOOM_ALLOWED)
        if zoommax:
            dialog1_views_zoommax.setValue(zoommax)
        else:
            dialog1_views_zoommax.setValue(MAXZOOM)
        self.dialog1_views.setCellWidget(index, 5, dialog1_views_zoommax)


    def removeRowView(self, index):
        """Remove row from view table."""

        if index is None:
            self.messageBar.pushMessage(Utils.tr("Warning"), Utils.tr("You have to select a view in order to delete it"), level=Qgis.Warning, duration=3)
            return

        self.dialog1_views.removeRow(index)
        del(self.dialog1_views.btns[index])
        del(self.dialog1_views.layers[index])


    def showLayersDialog(self, viewListIndex):
        """Show layers dialog in case view has been selected."""

        # print("showLayersDialog", viewListIndex, self.dialog1_views.cellWidget(viewListIndex, 1).text())

        if viewListIndex < 0:
            self.messageBar.pushMessage(Utils.tr("Warning"), Utils.tr("You have to select a view in order to edit its layers"), level=Qgis.Warning, duration=3)
            return

        viewId = self.dialog1_views.cellWidget(viewListIndex, 0).currentText()
        viewName = self.dialog1_views.cellWidget(viewListIndex, 1).text()
        self.dlg11.loadData(viewListIndex, viewId, viewName)
        self.dlg11.show()


    def getViewList(self):
        """Get list of all views."""

        names = ["-"]
        for name in QgsProject.instance().mapThemeCollection().mapThemes():
            names.append(name)

        return names


    def getSelectedViewRow(self):
        """Get index of selected row from view table."""

        selRow = self.dialog1_views.selectionModel().selectedRows()
        if len(selRow) == 0:
            return None

        return selRow[0].row()


    def setViewName(self, viewId):
        """Select view and write view name field."""

        index = self.getSelectedViewRow()
        if index is None:
            return

        viewNameWidget = self.dialog1_views.cellWidget(index, 1)
        if viewId != "-":
            viewNameWidget.setText(viewId)
        else:
            viewNameWidget.setText("")

        # delete associated layers
        if index < len(self.dialog1_views.layers):
            self.dialog1_views.layers[index] = None

        #self.dlg11.loadData(index, viewId, viewName)
        #self.dlg11.saveData()


    def updateViewsAndLayerData(self):
        """In order to make sure that all views and layers are up to date, we have to check them."""

        # 1. Iterate over views and delete in case one doesn't exist.
        viewNames = self.getViewList()
        for viewIndex in range(self.dialog1_views.rowCount()):
            viewName = self.dialog1_views.cellWidget(viewIndex, 0).currentText()
            if viewName in viewNames:
                # update with actual layer data
                viewId = self.dialog1_views.cellWidget(viewIndex, 0).toolTip()
                self.dlg11.loadData(viewIndex, viewId, viewName)
                self.dlg11.saveData(viewIndex)
            else:
                # delete
                self.removeRowView(viewIndex)
                viewIndex-=1


    def exportMbtiles(self, mapsetPath, ogr2ogr=False, _removeGpkgs=True):
        """Write all vector layers selected by mapstore as mbtiles."""

        # initial cleanup of Gpkg files
        self.removeGpkg(mapsetPath)

        self.progress = Utils.initProgressBar(100, "Writing mbtiles...", self.messageBar)

        # update progress bar
        self.progress.setValue(self.progress.value() + 1)

        layers = []
        multipleMbtiles = self.dialog1_multiple_mbtiles.checkState() == 2

        # get all layers to write into one mbtiles file
        index = 0
        uniqueIds=[]
        layersConf = {} # layer configuration as a JSon serialized string
        for viewLayers in self.dialog1_views.layers:

            if multipleMbtiles:
                layers = []

            if viewLayers:

                for viewLayer in viewLayers:

                    # only once if all layers in one single mbtiles file
                    if multipleMbtiles or viewLayer["id"] not in uniqueIds:

                        uniqueIds.append(viewLayer["id"])
                        layer = QgsProject.instance().mapLayer(viewLayer["id"])

                        # limit to view min and max zooms
                        maxzoom = min(round(self.getLayerMaxZoom(layer, index)), self.getViewZoomMax())
                        minzoom = min( max(round(self.getLayerMinZoom(layer, index)), self.getViewZoomMin()), maxzoom)

                        # https://gdal.org/drivers/raster/mbtiles.html
                        layersConf[viewLayer["id"]] = {
                            #"target_name": viewLayer["id"],
                            "minzoom": minzoom,
                            "maxzoom": maxzoom
                        }

                        dp = layer.dataProvider()
                        uri = dp.dataSourceUri()

                        uri = self.cleanLayer(layer, mapsetPath)

                        if ogr2ogr:
                            layers.append(uri)
                        else:
                            layers.append({'layer':uri})

                        #self.writeMapboxStyle(layer, mapsetPath, viewLayer["name"])

                # write one mbtile file per view
                if multipleMbtiles:
                    if ogr2ogr:
                        self.processMbtiles(index, layers, str(layersConf), mapsetPath, Utils.toAsciiAlnum(self.dialog1_name.text()) + "_" + Utils.toAsciiAlnum(self.dialog1_views.cellWidget(index, 1).text()), _removeGpkgs)
                    else:
                        self.processMbtilesNative(index, layers, mapsetPath, Utils.toAsciiAlnum(self.dialog1_name.text()) + "_" + Utils.toAsciiAlnum(self.dialog1_views.cellWidget(index, 1).text()))

            index += 1

        # update progress bar
        self.progress.setValue(self.progress.value() + 1)

        # write one mbtile file per project
        if not multipleMbtiles:
            # take zoom from first view in case of merging all into one mbtiles file
            if ogr2ogr:
                self.processMbtiles(0, layers, str(layersConf), mapsetPath, Utils.toAsciiAlnum(self.dialog1_name.text()), _removeGpkgs)
            else:
                self.processMbtilesNative(0, layers, mapsetPath, Utils.toAsciiAlnum(self.dialog1_name.text()))

        # remove progress bar
        self.messageBar.clearWidgets()

        # final cleanup of Gpkg files
        if _removeGpkgs:
            self.removeGpkg(mapsetPath)


    def getLayerMinZoom(self, layer, index):
        """Return max zoom. Use scale based visibililty if defined, or view if not."""

        if layer.hasScaleBasedVisibility():
            return Utils.getZoomFromScale(layer.minimumScale())
        
        return int(self.dialog1_views.cellWidget(index, 4).text())


    def getLayerMaxZoom(self, layer, index):
        """Return max zoom. Use scale based visibililty if defined, or view if not."""

        if layer.hasScaleBasedVisibility():
            return Utils.getZoomFromScale(layer.maximumScale())
        
        return int(self.dialog1_views.cellWidget(index, 5).text())


    def processMbtiles(self, index, layers, layersConf, exportPath, fileName, _removeGpkgs):
        """Run ogr2ogr process to write mbtiles."""

        # update progress bar
        self.progress.setValue(self.progress.value() + 1)

        if self._printLog:
            print("layers to package", layers)

        ## package layers into one gpkg
        finalGpkg = os.path.join(exportPath, fileName + '.gpkg')
        inn = {
            'LAYERS': layers,
            'OVERWRITE': True,
            'SAVE_STYLES': False,
            'SAVE_METADATA': True,
            'SELECTED_FEATURES_ONLY': False,
            'EXPORT_RELATED_LAYERS': False,
            'OUTPUT': finalGpkg
        }
        processing.run("native:package", inn)

        # update progress bar
        self.progress.setValue(self.progress.value() + 1)

        if self._printLog:
            print("layersConf", layersConf)
            print("output file", fileName + '.mbtiles')

        ## write mbtiles file
        params = {
            'INPUT': finalGpkg,
            'CONVERT_ALL_LAYERS': True,
            'OPTIONS':
            '-dsco MAX_SIZE=10000000 ' +
            '-dsco MAX_FEATURES=10000000 ' +
            #'-dsco SIMPLIFICATION=0.1 ' +
            #'-dsco BUFFER=120 ' +
            #'-dsco BOUNDS=' + Utils.getExtentBoundsProj(self.dialog1_extent.text(), 4326) ' +
            ' -dsco CONF="' + layersConf + '"' +
            ' -dsco MINZOOM=' + str(self.getViewZoomMin()) +
            ' -dsco MAXZOOM=' + str(self.getViewZoomMax()),
            'OUTPUT': os.path.join(exportPath, fileName + '.mbtiles')
        }

        feedback = QgsProcessingFeedback()
        feedback.progressChanged.connect(lambda:self.progress.setValue(self.progress.value() + 1))

        # def onFinish(_alg, _context, _feedback):
        #     if _removeGpkgs:
        #         self.removeGpkg(exportPath)
        #     return

        #processing.run("qwv:gpkg2mbtiles", params, feedback=feedback, onFinish=onFinish)

        processing.run("qwv:gpkg2mbtiles", params, feedback=feedback)


    def getViewZoomMin(self):
        """Return min zoom of all views."""

        minZoomViews = MAXZOOM_ALLOWED
        for index in range(self.dialog1_views.rowCount()):
            minZoom = self.dialog1_views.cellWidget(index, 4).value()
            if minZoom < minZoomViews:
                minZoomViews = minZoom

        return minZoomViews


    def getViewZoomMax(self):
        """Return max zoom of all views."""

        maxZoomViews = MINZOOM_ALLOWED
        for index in range(self.dialog1_views.rowCount()):
            maxZoom = self.dialog1_views.cellWidget(index, 5).value()
            if maxZoom > maxZoomViews:
                maxZoomViews = maxZoom

        return maxZoomViews


    def processMbtilesNative(self, index, layers, exportPath, fileName):
        """Run native process to write mbtiles."""

        if self._printLog:
            print("layers to export", layers)
            print("write to", os.path.join(exportPath, fileName + '.mbtiles'))

        extent = Utils.getExtentBoundsProj(self.dialog1_extent.text(), 3857)
        minzoom = str(self.getViewZoomMin())
        maxzoom = str(self.getViewZoomMax())

        # remove before creating
        mbtilesFile = os.path.join(exportPath, fileName + '.mbtiles')
        if os.path.exists(mbtilesFile):
            os.remove(mbtilesFile)

        params = {
            'OUTPUT': mbtilesFile,
            'LAYERS': layers,
            'MIN_ZOOM': minzoom,
            'MAX_ZOOM': maxzoom,
            #'EXTENT': extent,
            'META_NAME': '',
            'META_DESCRIPTION': '',
            'META_ATTRIBUTION': '',
            'META_VERSION': '',
            'META_TYPE': None,
            'META_CENTER': ''
        }

        feedback = QgsProcessingFeedback()
        feedback.progressChanged.connect(lambda:self.progress.setValue(self.progress.value() + 1))
        processing.run("native:writevectortiles_mbtiles", params, feedback=feedback)

        #if _removeGpkgs:
        #    self.removeGpkg(exportPath)


    def removeGpkg(self, path):
        """Remove all layer files from folder."""

        for file in os.listdir(path):
            if file.endswith(".gpkg") or file.endswith(".gpkg-shm") or file.endswith(".gpkg-wal"):
                try:
                    #time.sleep(2)   # something happens on windows as some gpkg files are impossible to delete...
                    os.remove(os.path.join(path, file))
                except Exception as e:
                    print(e)
                    self.messageBar.pushMessage(Utils.tr("Warning"), Utils.tr("Could not remove GPKG ") + os.path.join(path, file), level=Qgis.Warning, duration=3)


    def cleanLayer(self, layer, exportPath):

        # avoid processing if final Gpkg file already does exist
        finalfile = os.path.join(exportPath, layer.id() + '.gpkg')
        if os.path.exists(finalfile):
            return finalfile

        ## 1. export file
        file1 = os.path.join(exportPath, layer.id() + '_1.gpkg')

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GPKG"
        options.fileEncoding = "UTF-8"
        options.layerName = layer.name()            
        options.filterExtent = Utils.getExtentRectangleProj(self.dialog1_extent.text(), 3857)
        options.ct = QgsCoordinateTransform(layer.crs(), QgsCoordinateReferenceSystem.fromEpsgId(3857), QgsProject.instance())

        QgsVectorFileWriter.writeAsVectorFormatV3(layer, file1, QgsProject.instance().transformContext(), options)

        ## 2. fix duplicated points
        file2 = file1.replace('_1.gpkg', '_2.gpkg')
        inn = {
            "INPUT": file1,
            #"OUTPUT": file2,
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
            "TOLERANCE": 0.001,
            "USE_Z_VALUE": False
        }
        proc2 = processing.run("native:removeduplicatevertices", inn)

        ## 3. fix geometries
        file3 = file2.replace('_2.gpkg', '_3.gpkg')
        inn = {
            #"INPUT": file2,
            #"OUTPUT": file3,
            "INPUT": proc2['OUTPUT'],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        proc3 = processing.run("native:fixgeometries", inn)

        ## 4. fix right to left
        file4 = file3.replace('_3.gpkg', '_4.gpkg')
        inn = {
            #"INPUT": file3,
            #"OUTPUT": file4,
            "INPUT": proc3['OUTPUT'],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        proc4 = processing.run("native:forcerhr", inn)

        ## 5. crop
        file5 = file4.replace('_4.gpkg', '_5.gpkg')
        inn = {
            #"INPUT": file4,
            #"OUTPUT": file5,
            "INPUT": proc4['OUTPUT'],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
            'EXTENT': self.dialog1_extent.text(),
            'CLIP':True,
        }
        proc5 = processing.run("native:extractbyextent", inn)
        
        ## 6. multi part to single part geometries
        file6 = file5.replace('_5.gpkg', '.gpkg')
        inn = {
            #"INPUT": file5,
            #"OUTPUT": file6,
            "INPUT": proc5['OUTPUT'],
            "OUTPUT": file6,
        }
        proc6 = processing.run("native:multiparttosingleparts", inn)

        return file6