# -*- coding: utf-8 -*-
"""
/***************************************************************************
 Mapbiomasfogo
                                 A QGIS plugin
 Este plugin permite acesso aos produtos de fogo do Mapbiomas diretamente no Qgis
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2025-06-05
        git sha              : $Format:%H$
        copyright            : (C) 2025 by IPAM Amazonia
        email                : contato@mapbiomas.org
 ***************************************************************************/
            Desenvolvimento do plugin: @IPAM - Brasília, DF - BR
 Newton Monteiro, Wallace Silva, Felipe Martenexen, Vera Laísa, João Ribeiro
                   contato:newton.monteiro@ipam.org.br
/***************************************************************************
 *                                                                         *
 *   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 json
import re
import traceback

from qgis.PyQt import sip
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, QVariant
from qgis.PyQt.QtCore import QTimer, QRectF, QObject, QThread, pyqtSignal
from .compat import Qt, QHeaderView, QAbstractItemView  # Qt5/Qt6 enum compatibility proxy
from qgis.PyQt.QtWidgets import (
    QAction,
    QApplication,
    QWidget,
    QVBoxLayout,
    QLabel,
    QPushButton,
    QMenu,
    QHBoxLayout,
    QDockWidget,
    QTableWidget,
    QTableWidgetItem,
    # QHeaderView,  # ❌ REMOVIDO - usa do compat.py (linha 42)
    QStyledItemDelegate,
    QStyleOptionViewItem,
)
from qgis.PyQt.QtGui import QColor, QPixmap, QIcon, QPainter
from qgis.core import (
    QgsRasterLayer,
    QgsProject,
    QgsVectorLayer,
    QgsField,
    QgsFeature,
    QgsGeometry,
    QgsCoordinateReferenceSystem,
    QgsCoordinateTransform,
    QgsRectangle,
)
from qgis.gui import QgsLayerTreeEmbeddedWidgetProvider, QgsGui

# Initialize Qt resources from file resources.py
from . import resources  # noqa: F401 - Qt resources required for UI files
# Import the code for the dialog
from .MapBiomas_fogo_dialog import MapbiomasfogoDialog
from .mapbiomas_api import MapBiomasApiClient
from .dynamic_legend import DynamicApiLegendProvider
from .parametros import ano_minimo, base_url, upload_base_url, collection
import os.path


class _DataBarDelegate(QStyledItemDelegate):
    """Delegate que desenha uma barra de dados no fundo da celula de legenda,
    proporcional ao valor da linha, com a cor da respectiva legenda."""

    # Transparencia da barra (0-255)
    BAR_ALPHA = 110

    def __init__(self, parent=None):
        super().__init__(parent)
        # Lista de (raw_value, hex_color) na mesma ordem das linhas da tabela.
        self._row_data = []
        self._max_value = 1.0

    def set_rows(self, row_data):
        """row_data: list of (raw_value, hex_color)."""
        self._row_data = row_data
        non_total = [v for v, c in row_data if v is not None and c != "transparent"]
        self._max_value = max(non_total) if non_total else 1.0

    def paint(self, painter, option, index):
        row = index.row()
        if row >= len(self._row_data):
            super().paint(painter, option, index)
            return

        raw_value, hex_color = self._row_data[row]
        is_total = (hex_color == "transparent" or raw_value is None)

        painter.save()

        # 1. Desenha a barra antes do texto
        if not is_total and raw_value and self._max_value > 0:
            ratio = min(float(raw_value) / self._max_value, 1.0)
            bar_width = int(option.rect.width() * ratio)
            bar_rect = QRectF(
                option.rect.left(),
                option.rect.top(),
                bar_width,
                option.rect.height(),
            )
            try:
                c = QColor(hex_color)
            except Exception:
                c = QColor("#CCCCCC")
            c.setAlpha(self.BAR_ALPHA)
            painter.fillRect(bar_rect, c)

        # 2. Texto e fundo de selecao por cima da barra (sem duplicar)
        super().paint(painter, option, index)

        painter.restore()


class _StatisticsTableItem(QTableWidgetItem):
    """Item com chave de ordenacao customizada e regra para manter 'Total' por ultimo."""

    ROLE_SORT_VALUE = Qt.ItemDataRole.UserRole + 11
    ROLE_IS_TOTAL = Qt.ItemDataRole.UserRole + 12

    def __init__(self, text, sort_value=None, is_total=False):
        super().__init__(text)
        self.setData(self.ROLE_SORT_VALUE, sort_value if sort_value is not None else text)
        self.setData(self.ROLE_IS_TOTAL, bool(is_total))

    def __lt__(self, other):
        if not isinstance(other, QTableWidgetItem):
            return super().__lt__(other)

        self_is_total = bool(self.data(self.ROLE_IS_TOTAL))
        other_is_total = bool(other.data(self.ROLE_IS_TOTAL))
        if self_is_total != other_is_total:
            return not self_is_total

        self_value = self.data(self.ROLE_SORT_VALUE)
        other_value = other.data(self.ROLE_SORT_VALUE)

        number_types = (int, float)
        if isinstance(self_value, number_types) and isinstance(other_value, number_types):
            return float(self_value) < float(other_value)

        return str(self_value or "").casefold() < str(other_value or "").casefold()


class _StatisticsFetchWorker(QObject):
    """Executa consulta de estatistica em thread separada para nao bloquear a UI."""

    finished = pyqtSignal(int, object)
    failed = pyqtSignal(int, str)

    def __init__(self, run_id, api_config, request_data, request_timeout):
        super().__init__()
        self._run_id = run_id
        self._api_config = dict(api_config or {})
        self._request_data = dict(request_data or {})
        self._request_timeout = request_timeout

    def run(self):
        try:
            client = MapBiomasApiClient(
                base_url=self._api_config.get("base_url") or base_url,
                upload_base_url=self._api_config.get("upload_base_url") or upload_base_url,
                timeout=self._request_timeout,
            )
            request_args = dict(self._request_data.get("request_args") or {})
            payload = client.get_area_statistics(
                requestTimeout=self._request_timeout,
                requestMaxAttempts=1,
                **request_args,
            )

            self.finished.emit(
                self._run_id,
                {
                    "payload": payload,
                    "legend_items": list(self._request_data.get("legend_items") or []),
                    "context": dict(self._request_data.get("context") or {}),
                },
            )
        except Exception as exc:
            self.failed.emit(self._run_id, str(exc))


class Mapbiomasfogo:
    DYNAMIC_LEGEND_PROVIDER_ID = "dynamicapilegend_v8"
    DEFAULT_STATISTICS_REQUEST_TIMEOUT = 30
    DEFAULT_STATISTICS_MAX_ATTEMPTS = 35
    DEFAULT_STATISTICS_RETRY_DELAY_MS = 2000

    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'Mapbiomasfogo_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&MapBiomas Fogo')
        self.api_client = MapBiomasApiClient(base_url=base_url, upload_base_url=upload_base_url)
        self._stats_docks = []
        self._dock_by_layer_id = {}
        self._closing_docks_from_layer = set()
        self._is_unloading = False
        self._layer_sequence = self._discover_max_layer_sequence()
        QgsProject.instance().layerWillBeRemoved.connect(self._on_project_layer_will_be_removed)

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('Mapbiomasfogo', message)


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = f'{self.plugin_dir}/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Acesse os dados de áera queimada'),
            callback=self.run,
            parent=self.iface.mainWindow())

        # will be set False in run()
        self.first_start = True


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        self._is_unloading = True
        self._prune_deleted_docks()
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&MapBiomas Fogo'),
                action)
            self.iface.removeToolBarIcon(action)

        for dock in list(self._stats_docks):
            try:
                if not sip.isdeleted(dock):
                    self.iface.removeDockWidget(dock)
                    dock.deleteLater()
            except RuntimeError:
                pass
        self._stats_docks = []
        self._dock_by_layer_id = {}
        self._closing_docks_from_layer.clear()

        try:
            QgsProject.instance().layerWillBeRemoved.disconnect(self._on_project_layer_will_be_removed)
        except (TypeError, RuntimeError):
            pass  # Signal already disconnected or object deleted

    def _prune_deleted_docks(self):
        """Remove referencias Python para docks ja destruidos no lado C++."""
        alive_docks = []
        for dock in self._stats_docks:
            try:
                if not sip.isdeleted(dock):
                    alive_docks.append(dock)
            except RuntimeError:
                continue
        self._stats_docks = alive_docks

        for layer_id, dock in list(self._dock_by_layer_id.items()):
            try:
                if sip.isdeleted(dock):
                    self._dock_by_layer_id.pop(layer_id, None)
            except RuntimeError:
                self._dock_by_layer_id.pop(layer_id, None)

    def _on_project_layer_will_be_removed(self, layer_id):
        if self._is_unloading:
            return

        if not isinstance(layer_id, str):
            try:
                layer_id = layer_id.id()
            except Exception:
                return

        dock = self._dock_by_layer_id.pop(layer_id, None)
        if dock is None:
            return

        self._closing_docks_from_layer.add(layer_id)
        if dock in self._stats_docks:
            self._stats_docks.remove(dock)

        try:
            if not sip.isdeleted(dock):
                self.iface.removeDockWidget(dock)
                dock.deleteLater()
        except RuntimeError:
            pass

    def _on_stats_dock_destroyed(self, layer_id):
        self._prune_deleted_docks()
        self._dock_by_layer_id.pop(layer_id, None)
        if layer_id in self._closing_docks_from_layer:
            self._closing_docks_from_layer.remove(layer_id)
            return

        if self._is_unloading:
            return

        layer = QgsProject.instance().mapLayer(layer_id)
        if layer is not None:
            QgsProject.instance().removeMapLayer(layer_id)

    @staticmethod
    def _strip_layer_index(name):
        return re.sub(r"^\s*#\s*\d+\s*-\s*", "", str(name or "")).strip()

    @staticmethod
    def _strip_temporal_suffix(name):
        """Remove sufixos temporais como 'em 2024', 'de 1985 a 2025' e 'ate 2025'."""
        text = str(name or "").strip()
        patterns = [
            r"\s+de\s+\d{4}\s+a\s+\d{4}\s*$",
            r"\s+ate\s+\d{4}\s*$",
            r"\s+até\s+\d{4}\s*$",
            r"\s+em\s+\d{4}\s*$",
            r"\s+para\s+\d{4}\s*$",
        ]
        for pattern in patterns:
            text = re.sub(pattern, "", text, flags=re.IGNORECASE)
        return re.sub(r"\s+", " ", text).strip()

    def _build_stats_dock_title(self, layer_name):
        full_name = str(layer_name or "").strip()
        return f"Estatisticas de {full_name}" if full_name else "Estatisticas"

    def _discover_max_layer_sequence(self):
        max_index = 0
        for layer in QgsProject.instance().mapLayers().values():
            match = re.match(r"^\s*#\s*(\d+)\s*-\s*", layer.name() or "")
            if match:
                max_index = max(max_index, int(match.group(1)))
        return max_index

    def _next_indexed_layer_name(self, base_name):
        self._layer_sequence += 1
        clean_name = self._strip_layer_index(base_name)
        return self._layer_sequence, f"#{self._layer_sequence} - {clean_name}"

    @staticmethod
    def _legend_item_label(legend_item):
        name_data = legend_item.get("name")
        if isinstance(name_data, dict):
            return (
                name_data.get("pt-BR")
                or name_data.get("en-US")
                or next(iter(name_data.values()), "Sem legenda")
            )
        if isinstance(name_data, str) and name_data.strip():
            return name_data.strip()
        return str(legend_item.get("key") or legend_item.get("pixelValue") or "Sem legenda")

    @staticmethod
    def _legend_child_pixel_values(legend_items):
        """Retorna os pixel values que pertencem a itens filhos da legenda."""
        child_pixel_values = set()
        for legend_item in legend_items or []:
            children = legend_item.get("children") or []
            if not isinstance(children, list):
                continue
            for child in children:
                pixel_value = child.get("pixelValue") if isinstance(child, dict) else None
                if pixel_value is not None:
                    child_pixel_values.add(pixel_value)
        return child_pixel_values

    @staticmethod
    def _format_statistics_label(label_text, pixel_value, child_pixel_values):
        base_label = str(label_text or "").strip()
        if pixel_value in child_pixel_values and base_label:
            return f"- {base_label}"
        return base_label

    @staticmethod
    def _format_stat_number(value, use_grouping=True):
        try:
            format_spec = ",.3f" if use_grouping else ".3f"
            number_text = format(float(value), format_spec)
            if use_grouping:
                return number_text.replace(",", "#").replace(".", ",").replace("#", ".")
            return number_text.replace(".", ",")
        except (TypeError, ValueError):
            return "0,000"

    @staticmethod
    def _format_stat_value(value, unit):
        unit_text = str(unit or "").strip()
        suffix = f" {unit_text}" if unit_text else ""
        return f"{Mapbiomasfogo._format_stat_number(value)}{suffix}"

    @staticmethod
    def _build_analysis_title(layer_name, year_values):
        if isinstance(year_values, list):
            clean_years = [str(year) for year in year_values if year is not None]
            if len(clean_years) == 1:
                return f"Analise de {layer_name} para {clean_years[0]}"
            if len(clean_years) >= 2:
                return f"Analise de {layer_name} de {clean_years[0]} a {clean_years[-1]}"
        if year_values is not None:
            return f"Analise de {layer_name} para {year_values}"
        return f"Analise de {layer_name}"

    @staticmethod
    def _resolve_selected_year_for_legend(legend_key, year, legend_year=None):
        """Resolve o ano de referencia usado para filtrar itens de legenda."""
        if legend_key == "fire_total_burned_last_year":
            return legend_year if isinstance(legend_year, int) else year if isinstance(year, int) else None

        if legend_key in {
            "fire_total_burned_accumulated",
            "fire_total_burned_frequency",
        }:
            if isinstance(year, list) and year:
                return year[-1]
            if isinstance(year, int):
                return year

        return None

    @classmethod
    def _resolve_statistics_year(cls, legend_key, year):
        """Normaliza o year esperado pelo endpoint statistics/area."""
        if legend_key == "fire_total_burned_mapbiomas_total_burned" and isinstance(year, int):
            try:
                min_year = int(ano_minimo)
            except (TypeError, ValueError):
                min_year = 1985
            return list(range(min_year, year + 1))
        return year

    @staticmethod
    def _resolve_statistics_year_series_anchor(legend_key, year):
        """Define quando a API deve retornar serie temporal no statistics/area."""
        if legend_key == "fire_total_burned_accumulated" and isinstance(year, list) and len(year) >= 2:
            return "start"
        return None

    @staticmethod
    def _format_statistics_period_label(year_values):
        """Converte o campo year da API em um rotulo legivel para a tabela."""
        if isinstance(year_values, list):
            clean_years = [str(year) for year in year_values if year is not None]
            if not clean_years:
                return "Sem periodo"
            if len(clean_years) == 1 or clean_years[0] == clean_years[-1]:
                return clean_years[0]
            return clean_years[-1]
        if year_values is None:
            return "Sem periodo"
        return str(year_values)

    def _build_statistics_request_data(self, layer):
        context_raw = layer.customProperty("firelegend/context_json", "{}")
        try:
            context = json.loads(context_raw) if context_raw else {}
        except json.JSONDecodeError:
            context = {}

        legend_key = context.get("legendKey")
        if not legend_key:
            raise ValueError("Nao foi possivel identificar legendKey da camada.")

        region = context.get("region") or "brazil"
        subtheme_key = context.get("subthemeKey")
        pixel_values = context.get("pixelValues") or []
        year = context.get("year")
        territory_ids = context.get("territoryIds")
        if isinstance(territory_ids, str):
            territory_ids_log = [territory_ids]
        elif isinstance(territory_ids, (list, tuple, set)):
            territory_ids_log = [str(item) for item in territory_ids if str(item).strip()]
        elif territory_ids is None:
            territory_ids_log = []
        else:
            territory_ids_log = [str(territory_ids)]

        if not subtheme_key:
            raise ValueError("Nao foi possivel identificar subthemeKey da camada.")

        # Para subthemas de acumulado/frequencia a API de estatisticas espera
        # apenas o ano final. Para fire_total_burned_last_year ela aceita o
        # intervalo completo e a lista de pixelValues.
        stats_year = self._resolve_statistics_year(legend_key, year)
        year_series_anchor = self._resolve_statistics_year_series_anchor(legend_key, stats_year)
        stats_pixel_values = pixel_values
        territory_category_id = 4 if legend_key == "fire_total_burned_mapbiomas_total_burned" else None
        property_code = "" if legend_key == "fire_total_burned_mapbiomas_total_burned" else None

        request_args = {
            "region": region,
            "subthemeKey": subtheme_key,
            "legendKey": legend_key,
            "pixelValue": stats_pixel_values,
            "year": stats_year,
            "territoryIds": territory_ids,
            "yearSeriesAnchor": year_series_anchor,
            "propertyCode": property_code,
            "territoryCategoryId": territory_category_id,
        }

        items_raw = layer.customProperty("firelegend/items_json", "[]")
        try:
            legend_items = json.loads(items_raw) if items_raw else []
        except json.JSONDecodeError:
            legend_items = []

        return {
            "context": context,
            "legend_items": legend_items,
            "request_args": request_args,
            "territory_ids_log": territory_ids_log,
        }

    @staticmethod
    def _resolve_statistics_fetch_policy(context):
        """Define timeout e retentativas por tipo de legenda para evitar travar a UI."""
        return {
            "request_timeout": Mapbiomasfogo.DEFAULT_STATISTICS_REQUEST_TIMEOUT,
            "max_attempts": Mapbiomasfogo.DEFAULT_STATISTICS_MAX_ATTEMPTS,
            "retry_delay_ms": Mapbiomasfogo.DEFAULT_STATISTICS_RETRY_DELAY_MS,
        }

    def _load_statistics_payload_from_request(
        self,
        request_data,
        request_timeout=30,
        request_max_attempts=1,
    ):
        context = dict((request_data or {}).get("context") or {})
        request_args = dict((request_data or {}).get("request_args") or {})
        territory_ids_log = list((request_data or {}).get("territory_ids_log") or [])

        print(
            "[MapBiomas Fogo][Estatisticas] Requisicao statistics/area -> "
            f"region={request_args.get('region')}, subthemeKey={request_args.get('subthemeKey')}, "
            f"legendKey={request_args.get('legendKey')}, year={request_args.get('year')}, "
            f"pixelValues={len(request_args.get('pixelValue') or [])}, territoryIds={territory_ids_log}, "
            f"yearSeriesAnchor={request_args.get('yearSeriesAnchor')}, "
            f"territoryCategoryId={request_args.get('territoryCategoryId')}, "
            f"timeout={request_timeout}s, maxAttempts={request_max_attempts}"
        )

        payload = self.api_client.get_area_statistics(
            requestTimeout=request_timeout,
            requestMaxAttempts=request_max_attempts,
            **request_args,
        )

        statistic_entries = payload.get("statistic") or []
        first_stat = statistic_entries[0] if statistic_entries else {}
        print(
            "[MapBiomas Fogo][Estatisticas] Resposta statistics/area -> "
            f"entries={len(statistic_entries)}, unit={payload.get('unit')}, "
            f"year={first_stat.get('year')}, total={first_stat.get('total')}"
        )

        legend_items = list((request_data or {}).get("legend_items") or [])
        return payload, legend_items, context

    def _populate_statistics_table(self, dock, layer_name, status_label, result_container, payload, legend_items, context):
        statistic_entries = payload.get("statistic") or []
        if not statistic_entries:
            raise ValueError("Arquivo de estatistica sem dados em 'statistic'.")

        stat_entry = statistic_entries[0]
        year_values = stat_entry.get("year")
        if year_values is None:
            year_values = context.get("year")

        table_widget = dock.findChild(QTableWidget, "statistics_table_widget")
        if table_widget is None:
            raise RuntimeError("Widgets de estatistica nao foram inicializados no painel.")

        unit = payload.get("unit", "")

        if context.get("legendKey") in {"fire_total_burned_accumulated", "fire_total_burned_mapbiomas_total_burned"} and len(statistic_entries) > 1:
            series_color = "#CCCCCC"
            for legend_item in legend_items:
                pixel_value = legend_item.get("pixelValue")
                if pixel_value is not None:
                    series_color = legend_item.get("color", "#CCCCCC")
                    break

            rows = []
            export_rows = []
            for stat_item in statistic_entries:
                period_years = stat_item.get("year")
                period_label = self._format_statistics_period_label(period_years)
                raw_value = stat_item.get("total", 0)
                rows.append((
                    series_color,
                    period_label,
                    self._format_stat_number(raw_value),
                    unit,
                    raw_value,
                    period_years,
                ))

                row_years = period_years if isinstance(period_years, list) else [period_years]
                row_years = [year for year in row_years if year is not None]
                export_rows.append({
                    "legenda": period_label,
                    "valor": raw_value,
                    "und": unit,
                    "ano_ini": row_years[0] if row_years else None,
                    "ano_fim": row_years[-1] if row_years else None,
                })

            def _series_sort_key(row_data):
                period_years = row_data[-1]
                if isinstance(period_years, list) and period_years:
                    end_year = period_years[-1]
                else:
                    end_year = period_years

                try:
                    return int(end_year)
                except (TypeError, ValueError):
                    return -1

            rows.sort(key=_series_sort_key, reverse=True)
            export_rows.sort(
                key=lambda row: int(row.get("ano_fim") or -1),
                reverse=True,
            )

            dock._statistics_export_payload = {
                "layer_name": layer_name,
                "unit": unit,
                "year": [],
                "rows": export_rows,
            }

            bar_delegate = _DataBarDelegate(table_widget)
            table_widget.setItemDelegateForColumn(1, bar_delegate)
            table_widget._bar_delegate = bar_delegate

            table_widget.setSortingEnabled(False)
            table_widget.setRowCount(len(rows))
            unit_header = f"Valor {unit}" if str(unit or "").strip() else "Valor"
            table_widget.setColumnCount(4)
            table_widget.setHorizontalHeaderLabels(["Cor", "Legenda", unit_header, "Und."])
            header = table_widget.horizontalHeader()
            if header is not None:
                header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
                header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
                header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
                header.setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
                header.setStretchLastSection(False)

            table_rows = []
            for legend_order, (color, label_text, value_text, unit_text, raw_value, _period_years) in enumerate(rows):
                table_rows.append({
                    "color": color,
                    "label": str(label_text),
                    "value_text": str(value_text),
                    "unit_text": str(unit_text or ""),
                    "raw_value": float(raw_value) if raw_value is not None else 0.0,
                    "is_total": False,
                    "legend_order": legend_order,
                })

            table_widget._statistics_rows = table_rows
            table_widget._statistics_sort_state = {"column": None, "order": None}
            self._render_statistics_table_rows(table_widget, table_rows)
            table_widget.resizeRowsToContents()
            print(
                "[MapBiomas Fogo][Estatisticas] Serie acumulada montada -> "
                f"layer={layer_name}, pontos={len(rows)}, total_final={rows[-1][4] if rows else 0} {unit}"
            )
            status_label.hide()
            result_container.show()
            return

        value_by_pixel = {}
        for item in stat_entry.get("items", []):
            pixel_value = item.get("pixelValue")
            if pixel_value is not None:
                value_by_pixel[pixel_value] = item.get("value", 0)

        rows = []
        export_rows = []
        child_pixel_values = self._legend_child_pixel_values(legend_items)
        for legend_item in legend_items:
            pixel_value = legend_item.get("pixelValue")
            if pixel_value is None:
                continue
            label_text = self._legend_item_label(legend_item)
            display_label = self._format_statistics_label(
                label_text,
                pixel_value,
                child_pixel_values,
            )
            raw_value = value_by_pixel.get(pixel_value, 0)
            color = legend_item.get("color", "#CCCCCC")
            formatted_number = self._format_stat_number(raw_value)
            rows.append((
                color,
                display_label,
                formatted_number,
                unit,
                raw_value,
            ))
            export_rows.append({
                "legenda": str(label_text),
                "valor": raw_value,
                "und": unit,
            })

        total_value = stat_entry.get("total", 0)
        rows.append(("transparent", "Total", self._format_stat_number(total_value), unit, total_value))
        export_rows.append({
            "legenda": "Total",
            "valor": total_value,
            "und": unit,
        })

        year_list = year_values if isinstance(year_values, list) else [year_values]
        dock._statistics_export_payload = {
            "layer_name": layer_name,
            "unit": unit,
            "year": [year for year in year_list if year is not None],
            "rows": export_rows,
        }

        # Configura delegate de barra de dados para a coluna Legenda
        bar_delegate = _DataBarDelegate(table_widget)
        table_widget.setItemDelegateForColumn(1, bar_delegate)
        # Guarda referencia para evitar coleta pelo GC
        table_widget._bar_delegate = bar_delegate

        table_widget.setSortingEnabled(False)
        table_widget.setRowCount(len(rows))
        unit_header = f"Valor {unit}" if str(unit or "").strip() else "Valor"
        table_widget.setColumnCount(4)
        table_widget.setHorizontalHeaderLabels(["Cor", "Legenda", unit_header, "Und."])
        header = table_widget.horizontalHeader()
        if header is not None:
            header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
            header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
            header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
            header.setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
            header.setStretchLastSection(False)

        table_rows = []
        for legend_order, (color, label_text, value_text, unit_text, raw_value) in enumerate(rows):
            table_rows.append({
                "color": color,
                "label": str(label_text),
                "value_text": str(value_text),
                "unit_text": str(unit_text or ""),
                "raw_value": float(raw_value) if raw_value is not None else 0.0,
                "is_total": str(label_text).strip().lower() == "total",
                "legend_order": legend_order,
            })

        table_widget._statistics_rows = table_rows
        table_widget._statistics_sort_state = {"column": None, "order": None}
        self._render_statistics_table_rows(table_widget, table_rows)
        table_widget.resizeRowsToContents()
        print(
            "[MapBiomas Fogo][Estatisticas] Tabela montada -> "
            f"layer={layer_name}, linhas={len(rows)}, total={total_value} {unit}"
        )
        status_label.hide()
        result_container.show()

    def _refresh_statistics_table_data_bars(self, table_widget):
        """Atualiza os dados da barra para refletir a ordem atual das linhas."""
        delegate = getattr(table_widget, "_bar_delegate", None)
        if delegate is None:
            return

        row_data = []
        for row in range(table_widget.rowCount()):
            label_item = table_widget.item(row, 1)
            if label_item is None:
                row_data.append((None, "transparent"))
                continue
            raw_value = label_item.data(Qt.ItemDataRole.UserRole + 1)
            color = label_item.data(Qt.ItemDataRole.UserRole + 2) or "transparent"
            row_data.append((raw_value, color))

        delegate.set_rows(row_data)
        table_widget.viewport().update()

    def _render_statistics_table_rows(self, table_widget, table_rows):
        """Renderiza linhas da tabela sem usar sort nativo do QTableWidget."""
        table_widget.setRowCount(len(table_rows))
        for row_index, row_data in enumerate(table_rows):
            color = row_data.get("color", "transparent")
            raw_value = row_data.get("raw_value", 0.0)
            label_text = row_data.get("label", "")

            color_item = QTableWidgetItem("")
            if color == "transparent":
                color_item.setBackground(QColor(0, 0, 0, 0))
            else:
                color_item.setBackground(QColor(color))
            color_item.setFlags(color_item.flags() & ~Qt.ItemFlag.ItemIsEditable)

            label_item = QTableWidgetItem(str(label_text))
            label_item.setData(Qt.ItemDataRole.UserRole + 1, raw_value)
            label_item.setData(Qt.ItemDataRole.UserRole + 2, color)
            label_item.setFlags(label_item.flags() & ~Qt.ItemFlag.ItemIsEditable)

            value_item = QTableWidgetItem(str(row_data.get("value_text", "")))
            value_item.setTextAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
            value_item.setFlags(value_item.flags() & ~Qt.ItemFlag.ItemIsEditable)

            unit_item = QTableWidgetItem(str(row_data.get("unit_text", "")))
            unit_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter | Qt.AlignmentFlag.AlignVCenter)
            unit_item.setFlags(unit_item.flags() & ~Qt.ItemFlag.ItemIsEditable)

            if row_data.get("is_total"):
                font = label_item.font()
                font.setBold(True)
                label_item.setFont(font)
                value_item.setFont(font)
                unit_item.setFont(font)

            table_widget.setItem(row_index, 0, color_item)
            table_widget.setItem(row_index, 1, label_item)
            table_widget.setItem(row_index, 2, value_item)
            table_widget.setItem(row_index, 3, unit_item)

        self._refresh_statistics_table_data_bars(table_widget)

    @staticmethod
    def _try_parse_numeric_label(label_text):
        text = str(label_text or "").strip()
        if not text:
            return None
        if re.fullmatch(r"\d+", text):
            try:
                return int(text)
            except ValueError:
                return None
        return None

    def _sort_statistics_rows(self, table_rows, column, order):
        """Ordena mantendo 'Total' fixo no final da lista."""
        normal_rows = [row for row in table_rows if not row.get("is_total")]
        total_rows = [row for row in table_rows if row.get("is_total")]
        reverse = order == Qt.SortOrder.DescendingOrder

        if column == 2:
            normal_rows.sort(key=lambda row: float(row.get("raw_value", 0.0)), reverse=reverse)
        elif column == 1:
            normal_rows.sort(key=lambda row: int(row.get("legend_order", 0)), reverse=reverse)

        return normal_rows + total_rows

    def _handle_statistics_header_click(self, table_widget, section):
        """Permite ordenacao apenas nas colunas Legenda (1) e Valor (2)."""
        if section not in (1, 2):
            return

        header = table_widget.horizontalHeader()
        if header is None:
            return

        sort_state = getattr(table_widget, "_statistics_sort_state", {"column": None, "order": None})
        current_column = sort_state.get("column")
        current_order = sort_state.get("order")
        if current_column == section:
            if current_order == Qt.SortOrder.AscendingOrder:
                next_order = Qt.SortOrder.DescendingOrder
            else:
                next_order = Qt.SortOrder.AscendingOrder
        else:
            next_order = Qt.SortOrder.AscendingOrder

        sort_state["column"] = section
        sort_state["order"] = next_order
        table_widget._statistics_sort_state = sort_state

        table_rows = list(getattr(table_widget, "_statistics_rows", []))
        sorted_rows = self._sort_statistics_rows(table_rows, section, next_order)
        table_widget._statistics_rows = sorted_rows
        self._render_statistics_table_rows(table_widget, sorted_rows)
        table_widget.resizeRowsToContents()
        header.setSortIndicator(section, next_order)

    @staticmethod
    def _copy_table_selection(table_widget):
        indexes = table_widget.selectedIndexes()
        if not indexes:
            indexes = [
                table_widget.model().index(row, col)
                for row in range(table_widget.rowCount())
                for col in range(table_widget.columnCount())
            ]
        if not indexes:
            return

        row_map = {}
        for index in indexes:
            if not index.isValid():
                continue
            row_map.setdefault(index.row(), {})[index.column()] = index.data() or ""

        lines = []
        for row in sorted(row_map.keys()):
            cols = row_map[row]
            line = "\t".join(str(cols.get(col, "")) for col in sorted(cols.keys()))
            lines.append(line)

        QApplication.clipboard().setText("\n".join(lines))

    def _show_stats_table_context_menu(self, table_widget, global_pos):
        menu = QMenu(table_widget)
        copy_action = menu.addAction("Copiar")
        selected_action = menu.exec(global_pos)
        if selected_action == copy_action:
            self._copy_table_selection(table_widget)

    def _export_statistics_data(self, dock, layer_name):
        payload = getattr(dock, "_statistics_export_payload", None)
        if not payload:
            self.iface.messageBar().pushWarning(
                "MapBiomas Fogo",
                "Gere a estatistica primeiro antes de exportar.",
            )
            return

        clean_layer_name = self._strip_layer_index(payload.get("layer_name") or layer_name)
        export_layer = QgsVectorLayer("None", f"Estatisticas - {clean_layer_name}", "memory")
        provider = export_layer.dataProvider()

        years = payload.get("year") or []
        year_start = years[0] if years else None
        year_end = years[-1] if years else None
        unit = str(payload.get("unit") or "")

        provider.addAttributes([
            QgsField("camada", QVariant.String),
            QgsField("legenda", QVariant.String),
            QgsField("valor", QVariant.Double),
            QgsField("valor_fmt", QVariant.String),
            QgsField("unidade", QVariant.String),
            QgsField("ano_ini", QVariant.Int),
            QgsField("ano_fim", QVariant.Int),
        ])
        export_layer.updateFields()

        features = []
        for row in payload.get("rows", []):
            raw_value = row.get("valor", 0)
            row_year_start = row.get("ano_ini", year_start)
            row_year_end = row.get("ano_fim", year_end)
            feature = QgsFeature(export_layer.fields())
            feature.setAttributes([
                clean_layer_name,
                str(row.get("legenda") or ""),
                float(raw_value) if raw_value is not None else 0.0,
                self._format_stat_number(raw_value, use_grouping=False),
                unit,
                int(row_year_start) if row_year_start is not None else None,
                int(row_year_end) if row_year_end is not None else None,
            ])
            features.append(feature)

        provider.addFeatures(features)
        previous_active_layer = self.iface.activeLayer()
        export_layer.setCustomProperty("mapbiomas_fogo/temp_export_layer", True)
        QgsProject.instance().addMapLayer(export_layer)
        self.iface.setActiveLayer(export_layer)

        action = self.iface.actionLayerSaveAs()
        try:
            if action is not None:
                action.trigger()
        finally:
            if QgsProject.instance().mapLayer(export_layer.id()) is not None:
                QgsProject.instance().removeMapLayer(export_layer.id())
            if previous_active_layer is not None:
                previous_layer_id = previous_active_layer.id()
                restored_layer = QgsProject.instance().mapLayer(previous_layer_id)
                if restored_layer is not None:
                    self.iface.setActiveLayer(restored_layer)

    def _setup_statistics_start_button(self, dock, layer_name, layer_id):
        """Conecta o botao de inicio e mostra mensagem de teste no painel."""
        try:
            start_button = getattr(dock, "Start_statistics_pushButton", None)
            panel_widget = getattr(dock, "Painel_Estatisticas_Dock", None)
            
            # If direct getattr didn't find them, try findChild
            if start_button is None:
                start_button = dock.findChild(QPushButton, "Start_statistics_pushButton")
            if panel_widget is None:
                panel_widget = dock.findChild(QWidget, "Painel_Estatisticas_Dock")
            
            if start_button is None or panel_widget is None:
                print(f"[MapBiomas Fogo] Erro: Widgets nao encontrados no dock (start_button={start_button is not None}, panel_widget={panel_widget is not None})")
                return

            panel_layout = panel_widget.layout()
            if panel_layout is None:
                print(f"[MapBiomas Fogo] panel_layout is None")
                return

            panel_layout.setContentsMargins(5, 5, 5, 5)
            panel_layout.setSpacing(6)

            # Remove os spacers do .ui para que o conteudo use toda a area do dock.
            for idx in range(panel_layout.count() - 1, -1, -1):
                item = panel_layout.itemAt(idx)
                if item is not None and item.spacerItem() is not None:
                    panel_layout.takeAt(idx)

            if hasattr(panel_layout, "setRowStretch") and hasattr(panel_layout, "setColumnStretch"):
                for idx in range(0, 6):
                    panel_layout.setRowStretch(idx, 0)
                    panel_layout.setColumnStretch(idx, 0)
                # O start_button já está em row=1 column=2 do .ui file
                # Não mexemos nele, apenas configuramos os stretchs
                # Row 0: vazio (para status quando necessário)
                # Row 1: start_button (já posicionado pelo .ui)
                # Row 2: result_container
                # Row 3: retry_button
                # Row 4: cancel_button
                panel_layout.setRowStretch(0, 0)  # Vazio não cresce
                panel_layout.setRowStretch(1, 0)  # Botão não cresce
                panel_layout.setRowStretch(2, 1)  # Resultado cresce
                panel_layout.setRowStretch(3, 0)  # Retry não cresce
                panel_layout.setRowStretch(4, 0)  # Cancel não cresce
                panel_layout.setColumnStretch(0, 0)
                panel_layout.setColumnStretch(1, 0)
                panel_layout.setColumnStretch(2, 1)  # Coluna central cresce

            status_label = panel_widget.findChild(QLabel, "statistics_status_label")
            if status_label is None:
                status_label = QLabel("")
                status_label.setObjectName("statistics_status_label")
                status_label.setWordWrap(True)
                status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
                status_label.setStyleSheet(
                    "QLabel#statistics_status_label {"
                    "background-color: transparent;"
                    "color: palette(text);"
                    "border: none;"
                    "border-radius: 0px;"
                    "padding: 5px;"
                    "font-weight: 600;"
                    "}"
                )
                # Adiciona status_label na linha 0, coluna 2 (acima do botão)
                if hasattr(panel_layout, "addWidget"):
                    panel_layout.addWidget(status_label, 0, 2, 1, 1)

            result_container = panel_widget.findChild(QWidget, "statistics_result_container")
            if result_container is None:
                result_container = QWidget(panel_widget)
                result_container.setObjectName("statistics_result_container")
                result_layout = QVBoxLayout(result_container)
                result_layout.setContentsMargins(0, 0, 0, 0)
                result_layout.setSpacing(8)

                table_widget = QTableWidget(result_container)
                table_widget.setObjectName("statistics_table_widget")
                table_widget.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
                table_widget.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectItems)
                table_widget.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
                
                table_widget.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
                table_widget.setSortingEnabled(False)
                table_widget.customContextMenuRequested.connect(
                    lambda pos, tw=table_widget: self._show_stats_table_context_menu(
                        tw,
                        tw.viewport().mapToGlobal(pos),
                    )
                )
                table_widget.verticalHeader().setVisible(False)
                header = table_widget.horizontalHeader()
                if header is not None:
                    header.setSortIndicatorShown(True)
                    header.setSectionsClickable(True)
                    header.setSortIndicator(1, Qt.SortOrder.AscendingOrder)
                    header.sectionClicked.connect(
                        lambda section, tw=table_widget: self._handle_statistics_header_click(
                            tw,
                            section,
                        )
                    )
                result_layout.addWidget(table_widget, 1)

                export_button = QPushButton("Exportar dados")
                export_button.setObjectName("statistics_export_button")
                export_button.clicked.connect(
                    lambda _checked=False, d=dock, ln=layer_name: self._export_statistics_data(d, ln)
                )
                result_layout.addWidget(export_button)

                # Adiciona result_container na linha 2, coluna 2 (abaixo do botão)
                if hasattr(panel_layout, "addWidget"):
                    panel_layout.addWidget(result_container, 2, 2, 1, 1)

            retry_button = panel_widget.findChild(QPushButton, "statistics_retry_button")
            if retry_button is None:
                retry_button = QPushButton("Tentar novamente")
                retry_button.setObjectName("statistics_retry_button")
                retry_button.setMinimumHeight(40)
                # Adiciona retry_button na linha 3, coluna 2
                if hasattr(panel_layout, "addWidget"):
                    panel_layout.addWidget(retry_button, 3, 2, 1, 1)

            cancel_button = panel_widget.findChild(QPushButton, "statistics_cancel_button")
            if cancel_button is None:
                cancel_button = QPushButton("Cancelar")
                cancel_button.setObjectName("statistics_cancel_button")
                cancel_button.setMinimumHeight(40)
                # Adiciona cancel_button na linha 4, coluna 2
                if hasattr(panel_layout, "addWidget"):
                    panel_layout.addWidget(cancel_button, 4, 2, 1, 1)

            # Oculta todos os widgets que não devem aparecer inicialmente
            status_label.hide()
            status_label.setFixedHeight(0)  # Força altura zero quando oculto
            status_label.setText("")  # Garante que não há texto
            result_container.hide()
            retry_button.hide()
            cancel_button.hide()
            
            # Garante que o botão start está visível e habilitado
            start_button.setVisible(True)
            start_button.setEnabled(True)
            start_button.raise_()  # Traz para frente no Z-order
            
            # Força atualização do layout
            panel_layout.update()
            panel_layout.activate()
            panel_widget.updateGeometry()
            from qgis.PyQt.QtWidgets import QApplication
            QApplication.processEvents()

            retry_state = {
                "run_id": 0,
                "attempt": 0,
                "request_data": None,
                "policy": {
                    "request_timeout": self.DEFAULT_STATISTICS_REQUEST_TIMEOUT,
                    "max_attempts": self.DEFAULT_STATISTICS_MAX_ATTEMPTS,
                    "retry_delay_ms": self.DEFAULT_STATISTICS_RETRY_DELAY_MS,
                },
            }
            loading_state = {"run_id": 0, "frame": 0}
            presentation_state = {"run_id": 0, "ticks": 0, "pending_render_run_id": None}
            active_job_state = {"job": None}
            start_button_default_text = start_button.text() or "Obter as estatisticas"
            loading_timer = QTimer(panel_widget)
            loading_timer.setInterval(450)

            # Funções helper para mostrar/ocultar status_label corretamente
            def _show_status_label(text=""):
                """Mostra o status_label com texto e restaura sua altura."""
                status_label.setMinimumHeight(0)
                status_label.setMaximumHeight(16777215)  # QWIDGETSIZE_MAX
                status_label.setText(text)
                status_label.show()
                panel_widget.updateGeometry()
            
            def _hide_status_label():
                """Oculta completamente o status_label."""
                status_label.hide()
                status_label.setFixedHeight(0)
                status_label.setText("")
                panel_widget.updateGeometry()


            def _animate_loading_text():
                if loading_state["run_id"] != retry_state["run_id"]:
                    loading_timer.stop()
                    return

                frames = ["\u00B7\u2024\u2024", "\u2024\u00B7\u2024", "\u2024\u2024\u00B7", "\u2024\u2024\u2024"]
                dots = frames[loading_state["frame"]]
                loading_state["frame"] = (loading_state["frame"] + 1) % len(frames)
                presentation_state["ticks"] += 1
                loading_text = f"Obtendo as estatisticas{dots}"
                status_label.setText(loading_text)

                pending_run_id = presentation_state.get("pending_render_run_id")
                if (
                    pending_run_id == retry_state["run_id"]
                    and presentation_state["ticks"] >= len(frames)
                ):
                    presentation_state["pending_render_run_id"] = None
                    _begin_statistics_render(pending_run_id)

            loading_timer.timeout.connect(_animate_loading_text)

            def _start_loading_animation(run_id):
                loading_state["run_id"] = run_id
                loading_state["frame"] = 0
                presentation_state["run_id"] = run_id
                presentation_state["ticks"] = 0
                status_label.setText("Obtendo as estatisticas...")
                start_button.setEnabled(False)
                if not loading_timer.isActive():
                    loading_timer.start()

            def _stop_loading_animation():
                loading_timer.stop()
                presentation_state["pending_render_run_id"] = None

            def _reset_start_button():
                start_button.setText(start_button_default_text)
                start_button.setEnabled(True)

            def _cleanup_worker_job(job):
                if not job:
                    return

                thread = job.get("thread")
                worker = job.get("worker")
                try:
                    if worker is not None:
                        worker.deleteLater()
                except RuntimeError:
                    pass  # Worker already deleted on C++ side
                try:
                    if thread is not None:
                        thread.quit()
                        thread.wait(200)
                        thread.deleteLater()
                except RuntimeError:
                    pass  # Thread already deleted on C++ side

                if active_job_state.get("job") is job:
                    active_job_state["job"] = None

            def _schedule_retry(run_id):
                if run_id != retry_state["run_id"]:
                    return

                retry_delay_ms = int(retry_state["policy"].get("retry_delay_ms") or 0)
                if retry_delay_ms <= 0:
                    _render_statistics_async(run_id)
                    return

                QTimer.singleShot(retry_delay_ms, lambda rid=run_id: _render_statistics_async(rid))

            def _render_statistics_async(run_id):
                if run_id != retry_state["run_id"]:
                    return

                active_job = active_job_state.get("job")
                if active_job is not None and active_job.get("thread") is not None:
                    if active_job["thread"].isRunning():
                        return
                    _cleanup_worker_job(active_job)

                retry_state["attempt"] += 1
                attempt_number = retry_state["attempt"]
                policy = dict(retry_state.get("policy") or {})
                max_attempts = int(policy.get("max_attempts") or 1)
                request_timeout = int(policy.get("request_timeout") or 30)
                request_data = retry_state.get("request_data")

                if not request_data:
                    _stop_loading_animation()
                    _reset_start_button()
                    start_button.hide()
                    result_container.hide()
                    status_label.setText("Falha ao obter as estatisticas")
                    status_label.show()
                    cancel_button.hide()
                    retry_button.show()
                    return

                # Mantem apenas a animacao durante a busca.

                worker = _StatisticsFetchWorker(
                    run_id=run_id,
                    api_config={
                        "base_url": self.api_client.base_url,
                        "upload_base_url": self.api_client.upload_base_url,
                    },
                    request_data=request_data,
                    request_timeout=request_timeout,
                )
                thread = QThread(panel_widget)
                worker.moveToThread(thread)
                job = {"thread": thread, "worker": worker, "run_id": run_id}
                active_job_state["job"] = job

                def _on_fetch_success(result_run_id, result_payload):
                    _cleanup_worker_job(job)

                    if result_run_id != retry_state["run_id"]:
                        return

                    try:
                        self._populate_statistics_table(
                            dock,
                            layer_name,
                            status_label,
                            result_container,
                            result_payload.get("payload") or {},
                            result_payload.get("legend_items") or [],
                            result_payload.get("context") or {},
                        )
                        _stop_loading_animation()
                        _reset_start_button()
                        start_button.hide()
                        retry_button.hide()
                        cancel_button.hide()
                    except Exception as exc:
                        print(
                            "[MapBiomas Fogo][Estatisticas] Erro ao montar tabela -> "
                            f"layer={layer_name}, tentativa={attempt_number}/{max_attempts}, erro={exc}"
                        )
                        result_container.hide()
                        if attempt_number < max_attempts:
                            print(
                                "[MapBiomas Fogo][Estatisticas] Falha ao processar tabela, nova tentativa -> "
                                f"layer={layer_name}, tentativa={attempt_number + 1}/{max_attempts}"
                            )
                            _schedule_retry(run_id)
                            return

                        _stop_loading_animation()
                        _reset_start_button()
                        print(
                            "[MapBiomas Fogo][Estatisticas] Falha ao processar tabela apos tentativas -> "
                            f"layer={layer_name}, tentativas={max_attempts}"
                        )
                        status_label.setText("Falha ao obter as estatisticas")
                        status_label.show()
                        cancel_button.hide()
                        retry_button.show()

                def _on_fetch_error(result_run_id, error_message):
                    _cleanup_worker_job(job)

                    if result_run_id != retry_state["run_id"]:
                        return
                    print(
                        "[MapBiomas Fogo][Estatisticas] Falha ao obter estatisticas -> "
                        f"layer={layer_name}, tentativa={attempt_number}/{max_attempts}, erro={error_message}"
                    )
                    result_container.hide()

                    if attempt_number < max_attempts:
                        print(
                            "[MapBiomas Fogo][Estatisticas] Nova tentativa apos falha de requisicao -> "
                            f"layer={layer_name}, proxima_tentativa={attempt_number + 1}/{max_attempts}"
                        )
                        _schedule_retry(run_id)
                        return

                    _stop_loading_animation()
                    _reset_start_button()
                    status_label.setText("Falha ao obter as estatisticas")
                    status_label.show()
                    cancel_button.hide()
                    retry_button.show()

                worker.finished.connect(_on_fetch_success)
                worker.failed.connect(_on_fetch_error)
                thread.started.connect(worker.run)
                thread.start()

            def _begin_statistics_render(run_id):
                if run_id != retry_state["run_id"]:
                    return

                start_button.hide()
                status_label.show()
                _render_statistics_async(run_id)

            def _start_statistics_placeholder():
                # Oculta botão e mostra status
                start_button.hide()
                _show_status_label("Carregando estatísticas...")
                
                layer = QgsProject.instance().mapLayer(layer_id)
                if layer is None:
                    _show_status_label(f"Nao foi possivel obter a camada para {layer_name}")
                    result_container.hide()
                    retry_button.show()
                    cancel_button.hide()
                    start_button.hide()
                    return

                try:
                    request_data = self._build_statistics_request_data(layer)
                    policy = self._resolve_statistics_fetch_policy(request_data.get("context"))
                except Exception as exc:
                    print(f"[MapBiomas Fogo][Estatisticas] Erro ao preparar request: {exc}")
                    traceback.print_exc()
                    _show_status_label(f"Falha ao preparar estatisticas: {exc}")
                    result_container.hide()
                    retry_button.show()
                    cancel_button.hide()
                    start_button.hide()
                    return

                retry_state["run_id"] += 1
                retry_state["attempt"] = 0
                retry_state["request_data"] = request_data
                retry_state["policy"] = policy

                _start_loading_animation(retry_state["run_id"])
                start_button.hide()
                _show_status_label()  # Mostra vazio durante loading animation
                result_container.hide()
                retry_button.hide()
                cancel_button.show()
                presentation_state["pending_render_run_id"] = retry_state["run_id"]
                QApplication.processEvents()

            def _cancel_statistics_attempts():
                retry_state["run_id"] += 1
                retry_state["attempt"] = 0
                retry_state["request_data"] = None
                _stop_loading_animation()
                _reset_start_button()

                active_job = active_job_state.get("job")
                if active_job is not None:
                    thread = active_job.get("thread")
                    if thread is not None:
                        try:
                            thread.requestInterruption()
                        except RuntimeError:
                            pass  # Thread already terminated

                start_button.hide()
                result_container.hide()
                status_label.setText("Operacao cancelada pelo usuario")
                status_label.show()
                cancel_button.hide()
                retry_button.show()

            start_button.clicked.connect(_start_statistics_placeholder)
            retry_button.clicked.connect(_start_statistics_placeholder)
            cancel_button.clicked.connect(_cancel_statistics_attempts)
        except Exception as e:
            print(f"[MapBiomas Fogo] Erro durante setup do statistics button: {e}")
            traceback.print_exc()

    def _show_statistics_dock(self, layer_name, layer_index, layer_id):
        """Abre o painel de estatisticas com o mesmo nome da camada adicionada."""
        self._prune_deleted_docks()
        
        # Detect QGIS version and load correct .ui file
        try:
            from qgis.core import Qgis
            qgis_version = int(Qgis.QGIS_VERSION.split('.')[0])
            if qgis_version >= 4:
                ui_file = "MapBiomas_fogo_dialog_painel_estatisticas_QGS4.ui"
            else:
                ui_file = "MapBiomas_fogo_dialog_painel_estatisticas_QGS3.ui"
        except (AttributeError, ValueError):
            ui_file = "MapBiomas_fogo_dialog_painel_estatisticas_QGS3.ui"
        
        ui_path = os.path.join(self.plugin_dir, ui_file)
        if not os.path.exists(ui_path):
            # Fallback: try without version suffix
            ui_path = os.path.join(self.plugin_dir, "MapBiomas_fogo_dialog_painel_estatisticas.ui")
        
        if not os.path.exists(ui_path):
            print(f"UI de painel de estatisticas nao encontrada: {ui_path}")
            return

        # QGIS 4 (PyQt6) fix: Use loadUiType because the UI file defines a QDockWidget as root
        try:
            print(f"[MapBiomas Fogo] Carregando UI do dock widget: {ui_path}")
            FORM_CLASS, BASE_CLASS = uic.loadUiType(ui_path)
            print(f"[MapBiomas Fogo] loadUiType returned: FORM_CLASS={FORM_CLASS}, BASE_CLASS={BASE_CLASS}")
            
            # Try to instantiate BASE_CLASS first (should be QDockWidget)
            dock = BASE_CLASS()
            print(f"[MapBiomas Fogo] BASE_CLASS instancia: {dock}, tipo: {type(dock)}")
            
            # Then setup the UI
            form = FORM_CLASS()
            form.setupUi(dock)
            print(f"[MapBiomas Fogo] setupUi chamado com sucesso")
            
            # Atualizar o número da coleção se o widget existir
            if hasattr(dock, 'Descriotion_download_3'):
                dock.Descriotion_download_3.setText(f"<html><head/><body><p><span style=\" font-weight:600;\">Selecione os anos desejados para carregar as cicatrizes de fogo da Coleção {collection}:</span></p></body></html>")
            
        except Exception as e:
            print(f"[MapBiomas Fogo] Erro ao carregar UI com loadUiType: {e}")
            traceback.print_exc()
            
            # Fallback: try loading directly
            try:
                print(f"[MapBiomas Fogo] Tentando fallback - criando QDockWidget e loadUi...")
                dock = QDockWidget()
                uic.loadUi(ui_path, dock)
                print(f"[MapBiomas Fogo] Fallback com loadUi funcionou")
                
                # Atualizar o número da coleção se o widget existir
                if hasattr(dock, 'Descriotion_download_3'):
                    dock.Descriotion_download_3.setText(f"<html><head/><body><p><span style=\" font-weight:600;\">Selecione os anos desejados para carregar as cicatrizes de fogo da Coleção {collection}:</span></p></body></html>")
            except Exception as e2:
                print(f"[MapBiomas Fogo] Fallback tambem falhou: {e2}")
                traceback.print_exc()
                return

        if not isinstance(dock, QDockWidget):
            print(f"[MapBiomas Fogo] UI nao carregou como QDockWidget. Tipo: {type(dock)}")
            return

        print(f"[MapBiomas Fogo] DockWidget valido, configurando...")
        dock.setObjectName(f"GET_Estastic_DockWidget_{layer_index}")
        dock.setWindowTitle(self._build_stats_dock_title(layer_name))
        dock.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
        dock.destroyed.connect(lambda _obj=None, lid=layer_id: self._on_stats_dock_destroyed(lid))
        dock.visibilityChanged.connect(
            lambda visible, d=dock: self._refresh_statistics_dock_view(d) if visible else None
        )
        self._setup_statistics_start_button(dock, layer_name, layer_id)

        previous_dock = self._stats_docks[-1] if self._stats_docks else None
        self.iface.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, dock)
        if previous_dock is not None:
            self.iface.mainWindow().tabifyDockWidget(previous_dock, dock)
            previous_dock.show()
        dock.show()
        dock.raise_()
        # Forca um ciclo de layout/ativacao para evitar travamento inicial das abas no QGIS.
        self.iface.mainWindow().update()
        self.iface.mainWindow().repaint()
        self._refresh_statistics_dock_view(dock)
        if previous_dock is not None:
            self._refresh_statistics_dock_view(previous_dock)
            QTimer.singleShot(0, previous_dock.raise_)
            QTimer.singleShot(0, lambda d=previous_dock: d.setFocus(Qt.FocusReason.OtherFocusReason))
        QTimer.singleShot(0, dock.raise_)
        QTimer.singleShot(0, lambda d=dock: d.setFocus(Qt.FocusReason.OtherFocusReason))
        self._schedule_statistics_dock_refresh(previous_dock, dock)
        self._stats_docks.append(dock)
        self._dock_by_layer_id[layer_id] = dock
        print(f"[MapBiomas Fogo] DockWidget adicionado com sucesso")

    def _schedule_statistics_dock_refresh(self, *docks):
        """Agenda repintura tardia para estabilizar abas tabificadas no QGIS."""
        main_window = self.iface.mainWindow()

        def _refresh_all():
            for dock in docks:
                self._refresh_statistics_dock_view(dock)
            if main_window is not None:
                main_window.updateGeometry()
                main_window.update()
                main_window.repaint()
            QApplication.processEvents()

        QTimer.singleShot(0, _refresh_all)
        QTimer.singleShot(150, _refresh_all)
        QTimer.singleShot(400, _refresh_all)

    def _refresh_statistics_dock_view(self, dock):
        """Forca repintura do dock/tab para evitar UI congelada ao alternar abas."""
        if dock is None:
            return

        try:
            table_widget = dock.findChild(QTableWidget, "statistics_table_widget")
            if table_widget is not None:
                table_widget.viewport().update()
                table_widget.updateGeometry()

            panel_widget = getattr(dock, "Painel_Estatisticas_Dock", None)
            if panel_widget is not None:
                panel_widget.updateGeometry()
                panel_widget.update()

            dock.updateGeometry()
            dock.update()
            dock.repaint()
            self.iface.mainWindow().update()
            QApplication.processEvents()
        except Exception as exc:
            print(f"[MapBiomas Fogo][Estatisticas] Falha ao atualizar dock: {exc}")

    def _ensure_dynamic_legend_provider(self):
        """Registra o provider de legenda dinâmica se ainda não estiver no QGIS."""
        registry = QgsGui.layerTreeEmbeddedWidgetRegistry()
        if not registry.provider(self.DYNAMIC_LEGEND_PROVIDER_ID):
            registry.addProvider(DynamicApiLegendProvider())

    def _attach_dynamic_legend(self, layer, legend_items, context):
        """Associa à camada uma legenda baseada em cor e nome retornados pela API."""
        self._ensure_dynamic_legend_provider()
        layer.setCustomProperty('embeddedWidgets/count', 1)
        layer.setCustomProperty('embeddedWidgets/0/id', self.DYNAMIC_LEGEND_PROVIDER_ID)
        layer.setCustomProperty("firelegend/items_json", json.dumps(legend_items, ensure_ascii=False))
        layer.setCustomProperty("firelegend/context_json", json.dumps(context, ensure_ascii=False))

    @staticmethod
    def _safe_filename(text):
        """Converte uma chave em nome de arquivo seguro para o sistema."""
        return re.sub(r"[^A-Za-z0-9_\-]", "_", text)

    def _save_legend_payload(self, legend_key, payload):
        """Salva arquivo JSON da legenda por subtema, no padrão Legend_<legend_key>.json."""
        filename = f"Legend_{self._safe_filename(legend_key)}.json"
        cache_dir = os.path.join(self.plugin_dir, "legend_cache")
        os.makedirs(cache_dir, exist_ok=True)
        store_path = os.path.join(cache_dir, filename)
        with open(store_path, "w", encoding="utf-8") as file_obj:
            json.dump(payload, file_obj, ensure_ascii=False, indent=2)
        print(f"Legenda salva em: {store_path}")

    @staticmethod
    def _extract_year_from_legend_item(legend_item):
        """Extrai o ano de um item de legenda do tipo year_2025."""
        key = legend_item.get("key", "")
        match = re.search(r"year_(\d{4})", str(key))
        if match:
            return int(match.group(1))

        name = legend_item.get("name", {})
        if isinstance(name, dict):
            for value in name.values():
                if str(value).isdigit() and len(str(value)) == 4:
                    return int(value)
        return None

    def _filter_last_year_legend(self, legend_items, pixel_values, selected_year):
        """Mantém apenas os itens da legenda do último ano até o ano selecionado."""
        filtered_items = []
        filtered_pixel_values = []

        for item in legend_items:
            item_year = self._extract_year_from_legend_item(item)
            if item_year is None or item_year <= selected_year:
                filtered_items.append(item)
                if item.get("pixelValue") is not None:
                    filtered_pixel_values.append(item.get("pixelValue"))

        if not filtered_pixel_values:
            filtered_pixel_values = pixel_values

        return filtered_items, filtered_pixel_values

    def _filter_accumulated_legend(self, legend_items, pixel_values, selected_year):
        """Mantém anos de ano_minimo até selected_year, ordenando do mais recente para o mais antigo."""
        try:
            min_year = int(ano_minimo)
        except (TypeError, ValueError):
            min_year = 1985

        rows_with_year = []
        for item in legend_items:
            item_year = self._extract_year_from_legend_item(item)
            if item_year is None:
                continue
            if min_year <= item_year <= int(selected_year):
                rows_with_year.append((item_year, item))

        if not rows_with_year:
            return legend_items, pixel_values

        rows_with_year.sort(key=lambda pair: pair[0], reverse=True)
        ordered_items = [item for _year, item in rows_with_year]
        ordered_pixel_values = [item.get("pixelValue") for item in ordered_items if item.get("pixelValue") is not None]

        if not ordered_pixel_values:
            ordered_pixel_values = pixel_values

        return ordered_items, ordered_pixel_values

    @staticmethod
    def _extract_frequency_count_from_item(legend_item):
        """Extrai a contagem de vezes de um item tipo frequency_5 ou '5 vezes'."""
        key = legend_item.get("key", "")
        match = re.search(r"frequency_(\d+)", str(key))
        if match:
            return int(match.group(1))

        name = legend_item.get("name", {})
        if isinstance(name, dict):
            for value in name.values():
                match = re.search(r"(\d+)", str(value))
                if match:
                    return int(match.group(1))
        return None

    def _filter_frequency_legend(self, legend_items, pixel_values, selected_year):
        """Mantém somente as frequências compatíveis com o ano selecionado."""
        max_frequency = max(1, int(selected_year) - int(ano_minimo))
        filtered_items = []
        filtered_pixel_values = []

        for item in legend_items:
            item_frequency = self._extract_frequency_count_from_item(item)
            if item_frequency is None or item_frequency <= max_frequency:
                filtered_items.append(item)
                if item.get("pixelValue") is not None:
                    filtered_pixel_values.append(item.get("pixelValue"))

        if not filtered_pixel_values:
            filtered_pixel_values = pixel_values

        return filtered_items, filtered_pixel_values

    def _load_layer_from_api(self, region, subtheme_key, legend_key, year, layer_name, legend_year=None, territory_ids=None, zoom_to_territory=False):
        """Consulta pixel values + map URL e adiciona camada raster ao projeto."""
        legend_data = self.api_client.get_pixel_values_by_key(
            legend_key,
            region_name=region,
        )
        pixel_values = legend_data.get("pixelValues", [])
        legend_items = legend_data.get("legendItems", [])

        selected_year = self._resolve_selected_year_for_legend(
            legend_key,
            year,
            legend_year=legend_year,
        )

        if legend_key == "fire_total_burned_last_year" and isinstance(selected_year, int):
            legend_items, pixel_values = self._filter_last_year_legend(
                legend_items,
                pixel_values,
                selected_year,
            )
        elif legend_key == "fire_total_burned_accumulated" and isinstance(selected_year, int):
            legend_items, pixel_values = self._filter_accumulated_legend(
                legend_items,
                pixel_values,
                selected_year,
            )
        elif legend_key == "fire_total_burned_frequency" and isinstance(selected_year, int):
            legend_items, pixel_values = self._filter_frequency_legend(
                legend_items,
                pixel_values,
                selected_year,
            )

        map_url = self.api_client.get_map_url(
            region=region,
            subthemeKey=subtheme_key,
            legendKey=legend_key,
            pixelValue=pixel_values,
            year=year,
            territoryId=territory_ids,
        )

        legend_payload = {
            "region": region,
            "subthemeKey": subtheme_key,
            "legendKey": legend_key,
            "year": year,
            "mapUrl": map_url,
            "legendId": legend_data.get("legendId"),
            "pixelValues": pixel_values,
            "legendItems": legend_items,
            "territoryIds": territory_ids,
        }
        self._save_legend_payload(legend_key, legend_payload)

        if not map_url:
            print(f"API retornou URL vazia para {legend_key}.")
            return

        xyz_uri = f"type=xyz&url={map_url}"
        raster_layer = QgsRasterLayer(xyz_uri, layer_name, "wms")
        if raster_layer.isValid():
            layer_index, indexed_layer_name = self._next_indexed_layer_name(layer_name)
            raster_layer.setName(indexed_layer_name)
            legend_context = {
                "region": region,
                "subthemeKey": subtheme_key,
                "legendKey": legend_key,
                "year": year,
                "pixelValues": pixel_values,
                "territoryIds": territory_ids,
            }
            self._attach_dynamic_legend(raster_layer, legend_items, legend_context)
            QgsProject.instance().addMapLayer(raster_layer)
            print(f"[MapBiomas Fogo] Camada adicionada ao projeto: {indexed_layer_name}")
            self._show_statistics_dock(indexed_layer_name, layer_index, raster_layer.id())
            if zoom_to_territory:
                # QGIS 4 fix: Increase delay to ensure layer is fully rendered before zooming
                # Use 500ms minimum for QGIS 4/Qt6 rendering pipeline
                delay_ms = 500
                print(f"[MapBiomas Fogo] Agendando zoom para territorio em {delay_ms}ms")
                QTimer.singleShot(delay_ms, lambda r=region, tids=territory_ids: self._zoom_canvas_to_territory(r, tids))
        else:
            print(f"Erro ao carregar a camada raster para {legend_key}.")
            print(f"URL retornada: {map_url}")

    def _zoom_canvas_to_territory(self, region, territory_ids):
        """Ajusta o canvas ao limite da geometria do territoryId ativo."""
        print(f"[MapBiomas Fogo] _zoom_canvas_to_territory chamada: region={region}, territory_ids={territory_ids}")
        if not territory_ids:
            print("[MapBiomas Fogo] territory_ids vazio, cancelando zoom")
            return

        try:
            if isinstance(territory_ids, str):
                territory_ids_log = [territory_ids]
            else:
                territory_ids_log = [str(item) for item in territory_ids if str(item).strip()]

            print(f"[MapBiomas Fogo] Consultando geometria da API para: {territory_ids_log}")
            geometry_payload = self.api_client.get_territory_geometry(
                region_name=region,
                territoryIds=territory_ids,
            )
            if not geometry_payload:
                print(
                    "[MapBiomas Fogo] Geometria do territoryId nao retornada -> "
                    f"region={region}, territoryIds={territory_ids_log}"
                )
                return

            print(f"[MapBiomas Fogo] Geometria recebida da API, convertendo para QgsGeometry...")
            geometry = self._build_qgs_geometry_from_geojson(geometry_payload)
            if geometry is None or geometry.isEmpty():
                print(
                    "[MapBiomas Fogo] Geometria do territoryId veio vazia -> "
                    f"region={region}, territoryIds={territory_ids_log}"
                )
                return

            canvas = self.iface.mapCanvas()
            if canvas is None:
                print("[MapBiomas Fogo] mapCanvas nao disponivel")
                return

            source_crs = QgsCoordinateReferenceSystem("EPSG:4326")
            destination_crs = canvas.mapSettings().destinationCrs()
            extent = geometry.boundingBox()
            if destination_crs.isValid() and destination_crs != source_crs:
                transform = QgsCoordinateTransform(source_crs, destination_crs, QgsProject.instance())
                extent = transform.transformBoundingBox(extent)

            extent = QgsRectangle(extent)
            extent.scale(1.05)
            print(
                "[MapBiomas Fogo] Ajustando canvas pelo territoryId -> "
                f"territoryIds={territory_ids_log}, extent={extent.toString()}"
            )
            canvas.setExtent(extent)
            canvas.refresh()
            print("[MapBiomas Fogo] Zoom aplicado com sucesso")
        except Exception as exc:
            print(f"[MapBiomas Fogo] Falha ao ajustar o canvas pelo territoryId: {exc}")
            traceback.print_exc()

    @staticmethod
    def _build_qgs_geometry_from_geojson(geometry_payload):
        """Converte GeoJSON em QgsGeometry com fallback para versoes antigas do QGIS."""
        if not isinstance(geometry_payload, dict):
            return None

        geometry_json = json.dumps(geometry_payload, ensure_ascii=False)

        # QGIS mais novo pode ter QgsGeometry.fromGeoJson.
        from_geojson = getattr(QgsGeometry, "fromGeoJson", None)
        if callable(from_geojson):
            for candidate in (geometry_json.encode("utf-8"), geometry_json):
                try:
                    geometry = from_geojson(candidate)
                    if geometry is not None and not geometry.isEmpty():
                        return geometry
                except (TypeError, ValueError, AttributeError):
                    pass  # Try next encoding format

        # Fallback compativel com QGIS antigos via OGR -> WKT -> QgsGeometry.
        try:
            from osgeo import ogr

            ogr_geometry = ogr.CreateGeometryFromJson(geometry_json)
            if ogr_geometry is None:
                print("[MapBiomas Fogo] Falha ao converter GeoJSON para OGR geometry.")
                return None

            geometry_wkt = ogr_geometry.ExportToWkt()
            if not geometry_wkt:
                print("[MapBiomas Fogo] OGR geometry sem WKT para conversao.")
                return None

            geometry = QgsGeometry.fromWkt(geometry_wkt)
            if geometry is None or geometry.isEmpty():
                print("[MapBiomas Fogo] Falha ao converter WKT em QgsGeometry.")
                return None

            return geometry
        except Exception as exc:
            print(f"[MapBiomas Fogo] Falha no fallback OGR para QgsGeometry: {exc}")
            return None

    def _get_layer_requests(self):
        """Define todas as combinações de checkbox/subtema/legenda controladas pela API."""
        annual_year = self.dlg.FireAnualYear.value()
        monthly_year = self.dlg.FireMonthlyYear.value()
        accumulated_end_year = self.dlg.FireAcumulatedT1.value()
        frequency_end_year = self.dlg.FireFrequencyYearT1.value()
        last_end_year = self.dlg.FireLastYear.value()
        scar_size_year = self.dlg.FireSizeYear.value()
        return_interval_year = self.dlg.FireReturnIntervalYear.value()
        severity_year = self.dlg.FireSeverityYear.value()
        FireMeanReturnIntervalYear = self.dlg.FireMeanReturnIntervalYear.value()

        return [
            {
                "enabled": self.dlg.check_fire_annual_by_total_burned.isChecked(),
                "subtheme_key": "fire_total_burned",
                "legend_key": "fire_total_burned_mapbiomas_total_burned",
                "year": annual_year,
                "layer_name": f"Fogo anual - Área queimada total em {annual_year}",
            },
            {
                "enabled": self.dlg.check_fire_annual_by_class.isChecked(),
                "subtheme_key": "fire_total_burned",
                "legend_key": "fire_annual_burned_coverage_mapbiomas_coverage",
                "year": annual_year,
                "layer_name": f"Fogo anual - Uso e cobertura em {annual_year}",
            },
            {
                "enabled": self.dlg.check_fire_annual_by_natural_anthropic.isChecked(),
                "subtheme_key": "fire_total_burned",
                "legend_key": "fire_annual_burned_natural_and_anthropic_mapbiomas_natural_and_anthropic_use",
                "year": annual_year,
                "layer_name": f"Fogo anual - Natural e antrópico em {annual_year}",
            },
            {
                "enabled": self.dlg.check_fire_Monthly.isChecked(),
                "subtheme_key": "fire_monthly",
                "legend_key": "fire_monthly_mapbiomas_monthly",
                "year": monthly_year,
                "layer_name": f"Fogo mensal em {monthly_year}",
            },
            {
                "enabled": self.dlg.check_fire_accumulated_by_total_burned.isChecked(),
                "subtheme_key": "fire_total_burned_accumulated",
                "legend_key": "fire_total_burned_accumulated",
                "year": [ano_minimo, accumulated_end_year],
                "layer_name": f"Fogo acumulado - Área total de {ano_minimo} a {accumulated_end_year}",
            },
            {
                "enabled": self.dlg.check_fire_accumulated_by_class.isChecked(),
                "subtheme_key": "fire_total_burned_accumulated",
                "legend_key": "fire_annual_burned_coverage_mapbiomas_coverage",
                "year": [ano_minimo, accumulated_end_year],
                "layer_name": f"Fogo acumulado - Uso e cobertura de {ano_minimo} a {accumulated_end_year}",
            },
            {
                "enabled": self.dlg.check_fire_accumulated_by_natural_anthropic.isChecked(),
                "subtheme_key": "fire_total_burned_accumulated",
                "legend_key": "fire_annual_burned_natural_and_anthropic_mapbiomas_natural_and_anthropic_use",
                "year": [ano_minimo, accumulated_end_year],
                "layer_name": f"Fogo acumulado - Natural e antrópico de {ano_minimo} a {accumulated_end_year}",
            },
            {
                "enabled": self.dlg.check_fire_frequency.isChecked(),
                "subtheme_key": "fire_total_burned_frequency",
                "legend_key": "fire_total_burned_frequency",
                "year": [ano_minimo, frequency_end_year],
                "legend_year": frequency_end_year,
                "layer_name": f"Frequência de queimadas de {ano_minimo} a {frequency_end_year}",
            },
            {
                "enabled": self.dlg.check_fire_Last.isChecked(),
                "subtheme_key": "fire_total_burned_last_year",
                "legend_key": "fire_total_burned_last_year",
                "year": [ano_minimo, last_end_year],
                "legend_year": last_end_year,
                "layer_name": f"Ano do último fogo até {last_end_year}",
            },
            {
                "enabled": self.dlg.check_fire_size.isChecked(),
                "subtheme_key": "fire_scar_size",
                "legend_key": "fire_scar_size_mapbiomas_scar_size",
                "year": scar_size_year,
                "layer_name": f"Tamanho da cicatriz em {scar_size_year}",
            },
            {
                "enabled": self.dlg.check_fire_return_interval.isChecked(),
                "subtheme_key": "fire_fire_return",
                "legend_key": "fire_fire_return_mapbiomas_fire_return_interval",
                "year": return_interval_year,
                "layer_name": f"Intervalo de retorno em {return_interval_year}",
            },
            {
                "enabled": self.dlg.check_fire_severity.isChecked(),
                "subtheme_key": "fire_severity",
                "legend_key": "fire_severity_mapbiomas_severity",
                "year": severity_year,
                "layer_name": f"Severidade do fogo em {severity_year}",
            },
            {
                "enabled": self.dlg.check_FireMeanReturnIntervalYear.isChecked(),
                "subtheme_key": "fire_fire_return_mean_interval",
                "legend_key": "fire_fire_return_mean_interval",
                "year": [ano_minimo, FireMeanReturnIntervalYear],
                "layer_name": f"Intervalo médio de retorno do fogo em {FireMeanReturnIntervalYear}",
            }
            
        ]


    def run(self):
        """Run method that performs all the real work"""

        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if not hasattr(self, "dlg") or self.dlg is None:
            self.dlg = MapbiomasfogoDialog()
            self.first_start = False

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec()
        # See if OK was pressed
        if result:
            region = "brazil"
            territory_ids = self.dlg.get_selected_territory_ids() or []
            zoom_to_territory = False

            custom_territory_id = None
            try:
                custom_territory_id = self.dlg.upload_selected_user_geometry_territory(
                    self.api_client,
                    region_name=region,
                )
            except Exception as exc:
                warning_message = f"Falha ao enviar geometria customizada para API: {exc}"
                print(warning_message)
                self.iface.messageBar().pushWarning("MapBiomas Fogo", warning_message)

            if custom_territory_id:
                # Com geometria customizada, prioriza o mesmo fluxo da plataforma web.
                territory_ids = [custom_territory_id]
                print(f"Recorte ativo: geometria carregada (territoryId={custom_territory_id})")
            elif territory_ids:
                zoom_to_territory = True
                print(f"Recorte ativo: territorio selecionado ({territory_ids})")
            else:
                # Mantem o fluxo de recorte/zoom usando o territoryId oficial do Brasil.
                territory_ids = ["1-1-1"]
                zoom_to_territory = True
                print("Recorte ativo: Brasil inteiro (territoryId=1-1-1)")

            for request in self._get_layer_requests():
                if not request["enabled"]:
                    continue

                try:
                    self._load_layer_from_api(
                        region=region,
                        subtheme_key=request["subtheme_key"],
                        legend_key=request["legend_key"],
                        year=request["year"],
                        layer_name=request["layer_name"],
                        legend_year=request.get("legend_year"),
                        territory_ids=territory_ids,
                        zoom_to_territory=zoom_to_territory,
                    )
                except Exception as exc:
                    error_msg = f"Erro ao consultar API do MapBiomas para {request['legend_key']}: {exc}"
                    print(error_msg)
                    print("[MapBiomas Fogo] Verifique o console Python para detalhes. Use diagnostic_api.py para diagnosticar o problema.")