"""Zabbix service for real-time printer supply lookups."""

import logging
from typing import Dict, List, Optional

import requests
from flask import current_app

from shopdb.extensions import cache

logger = logging.getLogger(__name__)


class ZabbixService:
    """
    Zabbix API service for real-time printer supply lookups.

    Queries Zabbix by IP address to get current supply levels.
    Use getsuppliesbyip_cached() for cached lookups or
    getsuppliesbyip() for live data.

    Configuration:
        ZABBIX_ENABLED: Set to True to enable Zabbix integration (default: False)
        ZABBIX_URL: Zabbix API URL (e.g., http://zabbix.example.com:8080)
        ZABBIX_TOKEN: Zabbix API authentication token
    """

    CACHE_TTL = 600  # 10 minutes
    REACHABLE_CHECK_TTL = 60  # Check reachability every 60 seconds

    def __init__(self):
        self._url = None
        self._token = None
        self._enabled = None

    @property
    def isenabled(self) -> bool:
        """Check if Zabbix integration is enabled."""
        # Check database setting first, fall back to env var
        from shopdb.core.models import Setting
        db_enabled = Setting.get('zabbix_enabled')
        if db_enabled is not None:
            return bool(db_enabled)
        # Fall back to env var for backwards compatibility
        return current_app.config.get('ZABBIX_ENABLED', False)

    @property
    def isconfigured(self) -> bool:
        """Check if Zabbix is enabled and configured."""
        if not self.isenabled:
            return False
        # Check database settings first, fall back to env vars
        from shopdb.core.models import Setting
        self._url = Setting.get('zabbix_url') or current_app.config.get('ZABBIX_URL')
        self._token = Setting.get('zabbix_token') or current_app.config.get('ZABBIX_TOKEN')
        return bool(self._url and self._token)

    @property
    def isreachable(self) -> bool:
        """Check if Zabbix is reachable (cached for 60 seconds)."""
        if not self.isenabled or not self.isconfigured:
            return False

        cache_key = 'zabbix_reachable'
        cached = cache.get(cache_key)
        if cached is not None:
            return cached

        # Quick connectivity check with 500ms timeout
        try:
            response = requests.get(
                f"{self._url}/api_jsonrpc.php",
                timeout=0.5
            )
            reachable = response.status_code in (200, 401, 403, 405)
        except requests.RequestException:
            reachable = False

        cache.set(cache_key, reachable, timeout=self.REACHABLE_CHECK_TTL)
        logger.debug(f"Zabbix reachability check: {reachable}")
        return reachable

    def _apicall(self, method: str, params: Dict) -> Optional[Dict]:
        """Make a Zabbix API call."""
        if not self.isconfigured:
            return None

        payload = {
            'jsonrpc': '2.0',
            'method': method,
            'params': params,
            'auth': self._token,
            'id': 1
        }

        try:
            response = requests.post(
                f"{self._url}/api_jsonrpc.php",
                json=payload,
                headers={'Content-Type': 'application/json'},
                timeout=0.5  # 500ms timeout - fail fast if Zabbix is slow/unreachable
            )
            response.raise_for_status()
            data = response.json()

            if 'error' in data:
                logger.error(f"Zabbix API error: {data['error']}")
                return None

            return data.get('result')

        except requests.RequestException as e:
            logger.error(f"Zabbix API request failed: {e}")
            return None

    def gethostbyip(self, ip: str) -> Optional[Dict]:
        """Find a Zabbix host by IP address."""
        result = self._apicall('host.get', {
            'output': ['hostid', 'host', 'name'],
            'filter': {'ip': ip},
            'selectInterfaces': ['ip']
        })

        if result:
            return result[0] if result else None
        return None

    def getsuppliesbyip(self, ip: str) -> Optional[List[Dict]]:
        """
        Get printer supply levels by IP address.

        Returns list of supplies with name and level percentage.
        """
        # Find host by IP
        host = self.gethostbyip(ip)
        if not host:
            logger.debug(f"No Zabbix host found for IP {ip}")
            return None

        hostid = host['hostid']

        # Get supply-related items
        items = self._apicall('item.get', {
            'output': ['itemid', 'name', 'lastvalue', 'key_'],
            'hostids': hostid,
            'search': {
                'key_': 'supply'  # Common key pattern for printer supplies
            },
            'searchWildcardsEnabled': True
        })

        if not items:
            # Try alternate patterns
            items = self._apicall('item.get', {
                'output': ['itemid', 'name', 'lastvalue', 'key_'],
                'hostids': hostid,
                'search': {
                    'name': 'toner'
                },
                'searchWildcardsEnabled': True
            })

        if not items:
            return []

        supplies = []
        for item in items:
            try:
                level = int(float(item.get('lastvalue', 0)))
            except (ValueError, TypeError):
                level = 0

            supplies.append({
                'name': item.get('name', 'Unknown'),
                'level': level,
                'itemid': item.get('itemid'),
                'key': item.get('key_'),
            })

        return supplies

    def gethostid(self, ip: str) -> Optional[str]:
        """Get Zabbix host ID for an IP address."""
        host = self.gethostbyip(ip)
        return host['hostid'] if host else None

    def getsuppliesbyip_cached(self, ip: str) -> Optional[List[Dict]]:
        """Get printer supply levels with caching (10-minute TTL)."""
        cache_key = f'zabbix_supplies_{ip}'
        result = cache.get(cache_key)
        if result is not None:
            return result

        result = self.getsuppliesbyip(ip)
        if result is not None:
            cache.set(cache_key, result, timeout=self.CACHE_TTL)
        return result

    def clearcache(self, ip: str = None):
        """Clear cached supply data for one IP or all."""
        if ip:
            cache.delete(f'zabbix_supplies_{ip}')
        cache.delete('printers_low_supplies')
