""" Table manager for layouts. """

import logging

from enum import Enum
from typing import Optional

from qgis.core import QgsMasterLayoutInterface, QgsProject
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QAbstractButton, QDialog, QWidget

from lizmap.definitions.base import BaseDefinitions
from lizmap.definitions.definitions import LwcVersions
from lizmap.table_manager.base import TableManager
from lizmap.toolbelt.resources import plugin_name

LOGGER = logging.getLogger(plugin_name())


class TableManagerLayouts(TableManager):

    """ Table manager for layouts. """

    def __init__(
        self,
        parent: Optional[QWidget],
        definitions: BaseDefinitions,
        edition: Optional[QDialog],
        table: QWidget,
        edit_button: QAbstractButton,
        up_button: QAbstractButton,
        down_button: QAbstractButton,
    ):
        TableManager.__init__(
            self,
            parent,
            definitions,
            edition,
            table,
            None,
            edit_button,
            up_button,
            down_button,
        )

    @staticmethod
    def label_dictionary_list() -> str:
        """ The label in the CFG file prefixing the list. """
        return "list"

    def load_qgis_layouts(self, data: dict):
        """ Load QGIS layouts into the table. """
        LOGGER.debug("Loading all layouts from the QGIS project :")
        tmp_layout_cfg = {}
        if data:
            for layout in data.get(self.label_dictionary_list()):
                tmp = dict(layout)
                # Remove the name of the layout, it's now the key of the dictionary
                del tmp['layout']
                tmp_layout_cfg[layout.get('layout')] = tmp

        # Previous print from <= LWC 3.6 was activated or not
        # Do not break pre-existing format
        if self.parent:
            current_version = self.parent.current_lwc_version()
            if current_version:
                legacy_print_checkbox = (
                        self.parent.cbActivatePrint.isChecked() or current_version <= LwcVersions.Lizmap_3_6)
            else:
                legacy_print_checkbox = False
        else:
            legacy_print_checkbox = False

        # Build a lookup of QGIS layouts by name
        qgis_layouts_by_name = {
            layout.name(): layout
            for layout in QgsProject.instance().layoutManager().printLayouts()
        }

        # Determine the display order: use saved order from config, then append any new layouts
        if data and data.get(self.label_dictionary_list()):
            cfg_order = [item.get('layout') for item in data.get(self.label_dictionary_list())]
            # Keep only names that still exist in the project
            ordered_names = [name for name in cfg_order if name in qgis_layouts_by_name]
            # Append new layouts not in the saved config
            for name in qgis_layouts_by_name:
                if name not in ordered_names:
                    ordered_names.append(name)
        else:
            ordered_names = list(qgis_layouts_by_name.keys())

        for layout_name in ordered_names:
            layout = qgis_layouts_by_name[layout_name]
            # TODO check for report ?
            LOGGER.debug("  * reading layout {}".format(layout.name()))
            row = self.table.rowCount()
            self.table.setRowCount(row + 1)

            # We create the empty structure
            json = dict()

            # We fill with the layout name
            json['layout'] = layout.name()

            # We first fill with None or default values from definitions
            for key, values in self.definitions.layer_config.items():

                if key == 'layout':
                    continue

                json[key] = None
                default = values.get('default')
                if isinstance(default, Enum):
                    default = default.value['data']

                if default is not None:
                    # Be careful, default can an empty string...
                    json[key] = default

                if legacy_print_checkbox and key == 'dpi_available':
                    json['dpi_available'] = ('100', '200', '300')

                if legacy_print_checkbox and key == 'formats_available':
                    json['formats_available'] = ('pdf', 'png', 'jpeg', 'svg')

            # Then we override by the CFG file
            if layout.name() in tmp_layout_cfg:
                for item_key, cfg_value in tmp_layout_cfg[layout.name()].items():
                    json[item_key] = cfg_value

            self._edit_row(row, json)

    def layout_renamed(self, layout: QgsMasterLayoutInterface, new_name: str):
        """ When a layout has been renamed in the project. """
        # The 'layout' has already the new name !
        # Shame, I need to make a diff to find which one was it...
        _ = layout

        row = self.table.rowCount()

        lizmap_layouts = []
        for i in range(row):
            cell = self.table.item(i, 0)
            if not cell:
                continue

            lizmap_layouts.append(cell.data(Qt.ItemDataRole.UserRole))

        qgis_layouts = []
        for layout in QgsProject.instance().layoutManager().printLayouts():
            qgis_layouts.append(layout.name())

        # Make the diff
        diff = [x for x in lizmap_layouts if x not in qgis_layouts]

        # Logically, it must be only one in the diff...
        if len(diff) >= 2:
            # Sorry, I don't know which one it was.
            return
        if len(diff) == 0:
            # Strange, no diff
            # Nothing to do
            return

        old_name = diff[0]

        for i in range(row):
            cell = self.table.item(i, 0)
            if not cell:
                continue

            value = cell.data(Qt.ItemDataRole.UserRole)
            if value == old_name:
                LOGGER.info("Renaming layout from '{}' to '{}'".format(old_name, new_name))
                cell.setData(Qt.ItemDataRole.UserRole, new_name)
                cell.setText(new_name)
                break

    def layout_removed(self, name: str):
        """ When a layout has been removed from the project. """
        # A layout removed is the same behavior as a layer deleted in other tables.
        # We only need to make it as a list.
        self.layers_has_been_deleted([name])
