"""
SLMM Synchronization Service

This service ensures Terra-View roster is the single source of truth for SLM device configuration.
When SLM devices are added, edited, or deleted in Terra-View, changes are automatically synced to SLMM.
"""

import logging
import httpx
import os
from typing import Optional
from sqlalchemy.orm import Session

from backend.models import RosterUnit

logger = logging.getLogger(__name__)

SLMM_BASE_URL = os.getenv("SLMM_BASE_URL", "http://localhost:8100")


async def sync_slm_to_slmm(unit: RosterUnit) -> bool:
    """
    Sync a single SLM device from Terra-View roster to SLMM.

    Args:
        unit: RosterUnit with device_type="slm"

    Returns:
        True if sync successful, False otherwise
    """
    if unit.device_type != "slm":
        logger.warning(f"Attempted to sync non-SLM unit {unit.id} to SLMM")
        return False

    if not unit.slm_host:
        logger.warning(f"SLM {unit.id} has no host configured, skipping SLMM sync")
        return False

    # Disable polling if unit is benched (deployed=False) or retired
    # Only actively deployed units should be polled
    should_poll = unit.deployed and not unit.retired

    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            response = await client.put(
                f"{SLMM_BASE_URL}/api/nl43/{unit.id}/config",
                json={
                    "host": unit.slm_host,
                    "tcp_port": unit.slm_tcp_port or 2255,
                    "tcp_enabled": True,
                    "ftp_enabled": True,
                    "ftp_username": "USER",  # Default NL43 credentials
                    "ftp_password": "0000",
                    "poll_enabled": should_poll,  # Disable polling for benched or retired units
                    "poll_interval_seconds": 3600,  # Default to 1 hour polling
                }
            )

            if response.status_code in [200, 201]:
                logger.info(f"✓ Synced SLM {unit.id} to SLMM at {unit.slm_host}:{unit.slm_tcp_port or 2255}")
                return True
            else:
                logger.error(f"Failed to sync SLM {unit.id} to SLMM: {response.status_code} {response.text}")
                return False

    except httpx.TimeoutException:
        logger.error(f"Timeout syncing SLM {unit.id} to SLMM")
        return False
    except Exception as e:
        logger.error(f"Error syncing SLM {unit.id} to SLMM: {e}")
        return False


async def delete_slm_from_slmm(unit_id: str) -> bool:
    """
    Delete a device from SLMM database.

    Args:
        unit_id: The unit ID to delete

    Returns:
        True if deletion successful or device doesn't exist, False on error
    """
    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            response = await client.delete(
                f"{SLMM_BASE_URL}/api/nl43/{unit_id}/config"
            )

            if response.status_code == 200:
                logger.info(f"✓ Deleted SLM {unit_id} from SLMM")
                return True
            elif response.status_code == 404:
                logger.info(f"SLM {unit_id} not found in SLMM (already deleted)")
                return True
            else:
                logger.error(f"Failed to delete SLM {unit_id} from SLMM: {response.status_code} {response.text}")
                return False

    except httpx.TimeoutException:
        logger.error(f"Timeout deleting SLM {unit_id} from SLMM")
        return False
    except Exception as e:
        logger.error(f"Error deleting SLM {unit_id} from SLMM: {e}")
        return False


async def sync_all_slms_to_slmm(db: Session) -> dict:
    """
    Sync all SLM devices from Terra-View roster to SLMM.

    This ensures SLMM database matches Terra-View roster as the source of truth.
    Should be called on Terra-View startup and optionally via admin endpoint.

    Args:
        db: Database session

    Returns:
        Dictionary with sync results
    """
    logger.info("Starting full SLM sync to SLMM...")

    # Get all SLM units from roster
    slm_units = db.query(RosterUnit).filter_by(device_type="slm").all()

    results = {
        "total": len(slm_units),
        "synced": 0,
        "skipped": 0,
        "failed": 0
    }

    for unit in slm_units:
        # Skip units without host configured
        if not unit.slm_host:
            results["skipped"] += 1
            logger.debug(f"Skipped {unit.unit_type} - no host configured")
            continue

        # Sync to SLMM
        success = await sync_slm_to_slmm(unit)
        if success:
            results["synced"] += 1
        else:
            results["failed"] += 1

    logger.info(
        f"SLM sync complete: {results['synced']} synced, "
        f"{results['skipped']} skipped, {results['failed']} failed"
    )

    return results


async def get_slmm_devices() -> Optional[list]:
    """
    Get list of all devices currently in SLMM database.

    Returns:
        List of device unit_ids, or None on error
    """
    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            response = await client.get(f"{SLMM_BASE_URL}/api/nl43/_polling/status")

            if response.status_code == 200:
                data = response.json()
                return [device["unit_id"] for device in data["data"]["devices"]]
            else:
                logger.error(f"Failed to get SLMM devices: {response.status_code}")
                return None

    except Exception as e:
        logger.error(f"Error getting SLMM devices: {e}")
        return None


async def cleanup_orphaned_slmm_devices(db: Session) -> dict:
    """
    Remove devices from SLMM that are not in Terra-View roster.

    This cleans up orphaned test devices or devices that were manually added to SLMM.

    Args:
        db: Database session

    Returns:
        Dictionary with cleanup results
    """
    logger.info("Checking for orphaned devices in SLMM...")

    # Get all device IDs from SLMM
    slmm_devices = await get_slmm_devices()
    if slmm_devices is None:
        return {"error": "Failed to get SLMM device list"}

    # Get all SLM unit IDs from Terra-View roster
    roster_units = db.query(RosterUnit.id).filter_by(device_type="slm").all()
    roster_unit_ids = {unit.id for unit in roster_units}

    # Find orphaned devices (in SLMM but not in roster)
    orphaned = [uid for uid in slmm_devices if uid not in roster_unit_ids]

    results = {
        "total_in_slmm": len(slmm_devices),
        "total_in_roster": len(roster_unit_ids),
        "orphaned": len(orphaned),
        "deleted": 0,
        "failed": 0,
        "orphaned_devices": orphaned
    }

    if not orphaned:
        logger.info("No orphaned devices found in SLMM")
        return results

    logger.info(f"Found {len(orphaned)} orphaned devices in SLMM: {orphaned}")

    # Delete orphaned devices
    for unit_id in orphaned:
        success = await delete_slm_from_slmm(unit_id)
        if success:
            results["deleted"] += 1
        else:
            results["failed"] += 1

    logger.info(
        f"Cleanup complete: {results['deleted']} deleted, {results['failed']} failed"
    )

    return results
