# -*- coding: utf-8 -*-
"""
QFieldCloud Extension — Main entry point.

Implements BaseExtension lifecycle for the QFieldCloud integration module.
Manages SDK adapter, credentials, project builder, and UI components.
"""

import logging
import os
from typing import Any, Dict, List, Optional

from qgis.PyQt.QtCore import QCoreApplication

from ..base import BaseExtension, ExtensionMetadata

DEFAULT_QFIELDCLOUD_URL = "https://app.qfield.cloud/api/v1/"

logger = logging.getLogger('FilterMate.Extensions.QFieldCloud')

# Lazy availability flag — set on first check_dependencies() call
_QFIELDSYNC_AVAILABLE: Optional[bool] = None


def _check_qfieldsync_available() -> bool:
    """Check if qfieldsync plugin is installed and importable."""
    global _QFIELDSYNC_AVAILABLE
    if _QFIELDSYNC_AVAILABLE is None:
        try:
            from qfieldsync.core.cloud_api import CloudNetworkAccessManager  # noqa: F401
            _QFIELDSYNC_AVAILABLE = True
        except ImportError:
            _QFIELDSYNC_AVAILABLE = False
    return _QFIELDSYNC_AVAILABLE


class QFieldCloudExtension(BaseExtension):
    """
    QFieldCloud integration extension for FilterMate.

    Provides:
    - One-click export of filtered layers to QFieldCloud
    - Credential management (keyring + QgsSettings)
    - .qgs project generation with QFieldSync properties
    - Batch push for multiple zones

    Requires: qfieldcloud-sdk >= 0.8.0 (optional dependency)
    """

    EXTENSION_ID = "qfieldcloud"
    EXTENSION_VERSION = "1.0.0"

    @staticmethod
    def tr(message):
        return QCoreApplication.translate('QFieldCloudExtension', message)

    def __init__(self):
        super().__init__()
        self._iface = None
        self._credentials_manager = None
        self._sdk_adapter = None
        self._qfc_service = None
        self._signals = None
        self._qfc_button = None
        self._dockwidget = None
        self._menu_name = None
        self._settings_action = None

    @property
    def metadata(self) -> ExtensionMetadata:
        return ExtensionMetadata(
            id=self.EXTENSION_ID,
            name="QFieldCloud",
            version=self.EXTENSION_VERSION,
            description="Export filtered layers to QFieldCloud in one click",
            author="FilterMate Team / WYRE FTTH",
            min_qgis_version="3.28",
            dependencies=["qfieldsync"],
            optional_dependencies=["keyring"],
            icon_name="qfieldcloud.png",
        )

    def config_schema(self) -> Dict[str, Dict[str, Any]]:
        """Declare team-level options under ``EXTENSIONS.qfieldcloud``.

        These are non-sensitive settings that can live in FilterMate's
        config.json (shared across a team via a shared profile dir).
        Sensitive credentials (token, password) stay in OS keyring;
        per-user identity (username) stays in QgsSettings.
        """
        return {
            "server_url": {
                "value": DEFAULT_QFIELDCLOUD_URL,
                "description": (
                    "QFieldCloud API base URL. Defaults to the public "
                    "instance; override to point at a self-hosted "
                    "QFieldCloud deployment."
                ),
            },
            "default_project": {
                "value": "",
                "description": (
                    "Default QFieldCloud project name pre-filled in the "
                    "push dialog. Leave empty to require explicit entry."
                ),
            },
            "auto_package": {
                "value": True,
                "choices": [True, False],
                "description": (
                    "Trigger a packaging job automatically after a "
                    "successful push so the project is ready for QField "
                    "clients without extra clicks."
                ),
            },
            "default_srid": {
                "value": 4326,
                "min": 1024,
                "max": 999999,
                "description": (
                    "Default EPSG code used when generating the .qgs "
                    "project for QFieldCloud. 4326 (WGS84) is a portable "
                    "default; teams should set their local CRS here "
                    "(e.g. 31370 for Belgium, 2154 for France)."
                ),
            },
            "default_description": {
                "value": "",
                "description": (
                    "Default project description pre-filled in the push "
                    "dialog. Useful to boilerplate team-wide context."
                ),
            },
            "upload_timeout_seconds": {
                "value": 300,
                "min": 30,
                "max": 3600,
                "description": (
                    "Maximum time (seconds) to wait for a single file "
                    "upload to QFieldCloud before aborting."
                ),
            },
        }

    def check_dependencies(self) -> bool:
        """Check if QFieldSync plugin is installed."""
        return _check_qfieldsync_available()

    def missing_deps_hint(self) -> Dict[str, str]:
        """QFieldSync is a QGIS plugin — not a pip package."""
        return {
            "method": "qgis_plugin",
            "install_command": (
                "Extensions → Installer/Gérer les extensions → "
                "Chercher « QFieldSync » → Installer"
            ),
            "details": (
                "QFieldSync est publié par OPENGIS.ch dans le dépôt "
                "QGIS officiel. Aucun pip install requis."
            ),
        }

    def initialize(self, iface: Any) -> None:
        """
        Initialize QFieldCloud services.

        Creates credentials manager and signals. SDK adapter and push
        service are created lazily when needed (and only if SDK is available).
        """
        self._iface = iface

        # These modules have no SDK dependency
        from .credentials_manager import CredentialsManager
        from .signals import QFieldCloudSignals

        self._credentials_manager = CredentialsManager(extension=self)
        self._credentials_manager.migrate_legacy_qgssettings()
        self.register_service('credentials', self._credentials_manager)

        self._signals = QFieldCloudSignals()
        self.register_service('signals', self._signals)

        logger.info("QFieldCloud extension initialized")

    def create_ui(self, toolbar: Any, menu_name: str) -> List[Any]:
        """Create QFieldCloud menu entries (button is in dockwidget)."""
        from qgis.PyQt.QtGui import QAction

        actions = []
        parent = self._iface.mainWindow()

        # Settings action (menu only)
        settings_action = QAction(self.tr("QFieldCloud Settings..."), parent)
        settings_action.triggered.connect(self._on_settings_triggered)
        self._iface.addPluginToVectorMenu(menu_name, settings_action)
        actions.append(settings_action)

        self._menu_name = menu_name
        self._settings_action = settings_action
        self._actions = actions
        return actions

    def create_dockwidget_ui(self, dockwidget: Any) -> List[Any]:
        """Inject QFieldCloud export button into the dockwidget action bar."""
        from qgis.PyQt.QtCore import QSize, Qt
        from qgis.PyQt.QtGui import QCursor, QIcon
        from qgis.PyQt.QtWidgets import QPushButton

        plugin_dir = os.path.dirname(os.path.dirname(os.path.dirname(
            os.path.abspath(__file__)
        )))
        icon_path = os.path.join(plugin_dir, 'icons', 'qfield.png')
        if not os.path.isfile(icon_path):
            icon_path = os.path.join(plugin_dir, 'icons', 'export.png')

        # Copy size from existing export button for consistency
        export_btn = getattr(dockwidget, 'pushButton_action_export', None)
        icon_size = QSize(35, 35)
        if export_btn:
            icon_size = export_btn.iconSize()

        # Create the push button matching the style of existing action buttons
        btn = QPushButton(dockwidget)
        btn.setObjectName("pushButton_action_qfieldcloud")
        btn.setToolTip(self.tr("Export filtered layers to QFieldCloud"))
        btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        if os.path.isfile(icon_path):
            btn.setIcon(QIcon(icon_path))
        btn.setIconSize(icon_size)
        btn.setFlat(True)
        btn.setText("")
        btn.clicked.connect(self._on_push_triggered)

        # Copy size policy and constraints from export button
        if export_btn:
            btn.setMinimumSize(export_btn.minimumSize())
            btn.setMaximumSize(export_btn.maximumSize())
            btn.setSizePolicy(export_btn.sizePolicy())

        # Start disabled — enabled only when EXPORTING panel is active
        btn.setEnabled(False)

        # Register as dockwidget attribute so ActionBarManager can find it
        dockwidget.pushButton_action_qfieldcloud = btn

        # Find the action bar layout and insert after the export button
        layout = getattr(dockwidget, 'horizontalLayout_actions_bottom', None)

        if layout and export_btn:
            for i in range(layout.count()):
                item = layout.itemAt(i)
                if item and item.widget() == export_btn:
                    layout.insertWidget(i + 1, btn)
                    break
            else:
                layout.addWidget(btn)
        elif layout:
            layout.addWidget(btn)
        else:
            logger.warning("QFieldCloud: Could not find action bar layout in dockwidget")
            return []

        # Store reference for teardown
        self._qfc_button = btn
        self._dockwidget = dockwidget

        logger.info("QFieldCloud: Export button added to dockwidget action bar")
        return [btn]

    def teardown(self) -> None:
        """Cleanup all QFieldCloud resources."""
        # Disconnect and remove the dockwidget button
        if self._qfc_button is not None:
            try:
                self._qfc_button.clicked.disconnect(self._on_push_triggered)
            except (TypeError, RuntimeError):
                pass
            if self._dockwidget is not None:
                try:
                    delattr(self._dockwidget, 'pushButton_action_qfieldcloud')
                except AttributeError:
                    pass
                self._dockwidget = None
            self._qfc_button.setParent(None)
            self._qfc_button.deleteLater()
            self._qfc_button = None

        # Disconnect and remove the settings action from the plugin vector menu
        if self._settings_action is not None:
            try:
                self._settings_action.triggered.disconnect(self._on_settings_triggered)
            except (TypeError, RuntimeError):
                pass
            if self._iface is not None and self._menu_name:
                try:
                    self._iface.removePluginVectorMenu(self._menu_name, self._settings_action)
                except Exception as exc:
                    logger.warning("Failed to remove QFieldCloud menu entry: %s", exc)
            self._settings_action = None
        self._menu_name = None
        self._actions.clear()

        # Cleanup services
        self._sdk_adapter = None
        self._qfc_service = None
        self._credentials_manager = None
        self._signals = None

        self._services.clear()
        self._iface = None
        logger.info("QFieldCloud extension torn down")

    # ------------------------------------------------------------------
    # Lazy service initialization
    # ------------------------------------------------------------------

    def get_sdk_adapter(self):
        """
        Get or create the SDK adapter.

        Creates the adapter lazily using stored credentials.
        Returns None if credentials are not configured.
        """
        if self._sdk_adapter is not None:
            return self._sdk_adapter

        from .sdk_adapter import QFieldCloudAdapter

        # Create adapter using QFieldSync's CloudNetworkAccessManager
        self._sdk_adapter = QFieldCloudAdapter()

        # Try auto-login with QFieldSync's stored credentials
        if not self._sdk_adapter.is_authenticated:
            self._sdk_adapter.auto_login()

        self.register_service('adapter', self._sdk_adapter)
        return self._sdk_adapter

    def get_qfc_service(self):
        """
        Get or create the QFieldCloud service.

        Creates the service lazily with adapter and credentials.
        Returns None if SDK adapter is not available.
        """
        if self._qfc_service is not None:
            return self._qfc_service

        adapter = self.get_sdk_adapter()
        if adapter is None:
            return None

        from .service import QFieldCloudService

        self._qfc_service = QFieldCloudService(
            adapter=adapter,
            credentials_manager=self._credentials_manager,
            signals=self._signals,
        )
        self.register_service('push', self._qfc_service)
        return self._qfc_service

    def reset_adapter(self) -> None:
        """Reset SDK adapter (e.g., after credential change)."""
        self._sdk_adapter = None
        self._qfc_service = None
        if 'adapter' in self._services:
            del self._services['adapter']
        if 'push' in self._services:
            del self._services['push']

    # ------------------------------------------------------------------
    # UI action handlers
    # ------------------------------------------------------------------

    def _on_push_triggered(self) -> None:
        """Handle 'Export QFieldCloud' button click."""
        # Try to get adapter and auto-login
        adapter = self.get_sdk_adapter()
        if adapter is None or not adapter.is_authenticated:
            # No QFieldSync credentials either — open settings
            self._on_settings_triggered()
            return

        from .ui.push_dialog import QFieldCloudPushDialog

        dialog = QFieldCloudPushDialog(
            parent=self._iface.mainWindow(),
            extension=self,
            iface=self._iface,
        )
        dialog.exec()

    def _on_settings_triggered(self) -> None:
        """Handle 'QFieldCloud Settings' menu click."""
        from .ui.settings_dialog import QFieldCloudSettingsDialog

        dialog = QFieldCloudSettingsDialog(
            parent=self._iface.mainWindow(),
            extension=self,
        )
        if dialog.exec():
            # Credentials may have changed — reset adapter
            self.reset_adapter()
