from fastapi import FastAPI, APIRouter, Depends, HTTPException, status, BackgroundTasks
from dotenv import load_dotenv
from starlette.middleware.cors import CORSMiddleware
from motor.motor_asyncio import AsyncIOMotorClient
import os
import logging
from pathlib import Path
from datetime import datetime, timedelta
import uuid
from typing import List, Optional
import asyncio

from models import (
    User, UserCreate, UserLogin, Token, UserRole,
    Device, DeviceUpdate, DeviceStatus,
    ScanRequest, ScanResult, SNMPData, DashboardStats
)
from auth import (
    get_password_hash, verify_password, create_access_token,
    get_current_user, get_current_org, require_role, require_super_admin,
    init_auth_db
)
from scanner import NetworkScanner
from snmp_manager import snmp_manager
from monitoring import DeviceMonitor
from lldp_cdp_discovery import lldp_cdp_discovery
from mikrotik_manager import mikrotik_manager
from cisco_ssh_manager import cisco_ssh_manager
from huawei_olt_manager import HuaweiOLTManager
from topology import TopologyBuilder
from reports import ReportsEngine
from backup_manager import BackupManager
from firmware_manager import FirmwareManager
from asset_manager import AssetManager
from notifications import notification_manager
from universal_device_manager import universal_device_manager
from traffic_analyzer import TrafficAnalyzer
from ai_config_engine import AIConfigEngine
from ai_troubleshooter import AITroubleshooter
from admin_panel_manager import AdminPanelManager
from super_admin import router as super_admin_router, init_super_admin
from admin_user_management import router as admin_user_mgmt_router, init_admin_user_management
from support_ticket_system import router as support_ticket_router, init_support_ticket_system
from pydantic import BaseModel, EmailStr

ROOT_DIR = Path(__file__).parent
load_dotenv(ROOT_DIR / '.env')

# MongoDB connection
mongo_url = os.environ['MONGO_URL']
client = AsyncIOMotorClient(mongo_url)
db = client[os.environ['DB_NAME']]

# Collections
users_collection = db.users
devices_collection = db.devices
scans_collection = db.scans
alerts_collection = db.alerts
metrics_collection = db.device_metrics

# Initialize managers
huawei_olt = HuaweiOLTManager(cisco_ssh_manager)
topology_builder = TopologyBuilder(db)
reports_engine = ReportsEngine(db)
backup_manager = BackupManager(db)
firmware_manager = FirmwareManager(db)
asset_manager = AssetManager(db)
traffic_analyzer = TrafficAnalyzer(db)
ai_config_engine = AIConfigEngine(db)
ai_troubleshooter = AITroubleshooter(db)
admin_manager = AdminPanelManager(db)

# Create the main app
app = FastAPI(title="Network Management System")

# Create a router with the /api prefix
api_router = APIRouter(prefix="/api")

# Scanner instance
scanner = NetworkScanner()

# Monitoring instance
monitor = DeviceMonitor(db)
monitoring_task = None

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# ============================================
# Authentication Routes
# ============================================

@api_router.post("/auth/register", response_model=Token)
async def register(user_data: UserCreate):
    """Register a new user"""
    existing_user = await users_collection.find_one({"email": user_data.email})
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    user_count = await users_collection.count_documents({})
    is_first_user = user_count == 0
    role = UserRole.ADMIN if is_first_user else user_data.role

    org_id = None
    if is_first_user:
        org_id = str(uuid.uuid4())
        org = {
            "id": org_id,
            "name": "Default Organization",
            "plan": "free",
            "created_at": datetime.utcnow(),
            "features_enabled": admin_manager._get_default_features("free"),
            "max_users": 50,
            "max_devices": 500,
        }
        await db.organizations.insert_one(org)
    else:
        default_org = await db.organizations.find_one({}, sort=[("created_at", 1)])
        if default_org:
            org_id = default_org["id"]
    
    user = User(
        id=str(uuid.uuid4()),
        email=user_data.email,
        username=user_data.username,
        hashed_password=get_password_hash(user_data.password),
        role=role,
        created_at=datetime.utcnow(),
        is_active=True
    )
    
    user_dict = user.dict()
    user_dict["organization_id"] = org_id
    if is_first_user:
        user_dict["is_org_owner"] = True
    await users_collection.insert_one(user_dict)
    
    access_token = create_access_token(data={
        "sub": user.id,
        "email": user.email,
        "role": user.role.value,
        "org": org_id
    })
    
    return Token(
        access_token=access_token,
        token_type="bearer",
        user={
            "id": user.id,
            "email": user.email,
            "username": user.username,
            "role": user.role.value,
            "organization_id": org_id
        }
    )

@api_router.post("/auth/login", response_model=Token)
async def login(user_data: UserLogin):
    """Login user"""
    user_doc = await users_collection.find_one({"email": user_data.email})
    if not user_doc:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password"
        )
    
    if not verify_password(user_data.password, user_doc["hashed_password"]):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password"
        )
    
    org_id = user_doc.get("organization_id")

    if not org_id and user_doc["role"] != UserRole.SUPER_ADMIN.value:
        default_org = await db.organizations.find_one({}, sort=[("created_at", 1)])
        if default_org:
            org_id = default_org["id"]
            await users_collection.update_one(
                {"id": user_doc["id"]},
                {"$set": {"organization_id": org_id}}
            )
    
    access_token = create_access_token(data={
        "sub": user_doc["id"],
        "email": user_doc["email"],
        "role": user_doc["role"],
        "org": org_id
    })
    
    return Token(
        access_token=access_token,
        token_type="bearer",
        user={
            "id": user_doc["id"],
            "email": user_doc["email"],
            "username": user_doc["username"],
            "role": user_doc["role"],
            "organization_id": org_id,
            "is_super_admin": user_doc["role"] == UserRole.SUPER_ADMIN.value
        }
    )

@api_router.get("/auth/me")
async def get_me(current_user: dict = Depends(get_current_user)):
    """Get current user info"""
    user_doc = await users_collection.find_one({"id": current_user["sub"]})
    if not user_doc:
        raise HTTPException(status_code=404, detail="User not found")
    
    return {
        "id": user_doc["id"],
        "email": user_doc["email"],
        "username": user_doc["username"],
        "role": user_doc["role"],
        "organization_id": user_doc.get("organization_id"),
        "is_super_admin": user_doc["role"] == UserRole.SUPER_ADMIN.value,
        "phone": user_doc.get("phone"),
        "avatar_url": user_doc.get("avatar_url"),
    }


class SelfProfileUpdate(BaseModel):
    username: Optional[str] = None
    phone: Optional[str] = None
    avatar_url: Optional[str] = None


class SuperAdminEmailChange(BaseModel):
    user_id: str
    new_email: EmailStr


@api_router.put("/auth/profile")
async def update_own_profile(
    data: SelfProfileUpdate,
    current_user: dict = Depends(get_current_user),
):
    """Update the authenticated user's own profile.
    All roles can update username, phone, and avatar. Email cannot be changed here."""
    user_doc = await users_collection.find_one({"id": current_user["sub"]})
    if not user_doc:
        raise HTTPException(status_code=404, detail="User not found")

    update_data = {}
    if data.username is not None:
        if len(data.username.strip()) < 2:
            raise HTTPException(status_code=400, detail="Username must be at least 2 characters")
        update_data["username"] = data.username.strip()
    if data.phone is not None:
        update_data["phone"] = data.phone.strip()
    if data.avatar_url is not None:
        update_data["avatar_url"] = data.avatar_url.strip()

    if not update_data:
        raise HTTPException(status_code=400, detail="No fields to update")

    update_data["updated_at"] = datetime.utcnow()
    await users_collection.update_one({"id": current_user["sub"]}, {"$set": update_data})

    updated = await users_collection.find_one({"id": current_user["sub"]})
    return {
        "id": updated["id"],
        "email": updated["email"],
        "username": updated["username"],
        "role": updated["role"],
        "organization_id": updated.get("organization_id"),
        "is_super_admin": updated["role"] == UserRole.SUPER_ADMIN.value,
        "phone": updated.get("phone"),
        "avatar_url": updated.get("avatar_url"),
    }


@api_router.put("/auth/change-email")
async def change_user_email(
    data: SuperAdminEmailChange,
    current_user: dict = Depends(require_super_admin),
):
    """Super admin only: change any user's email address."""
    target_user = await users_collection.find_one({"id": data.user_id})
    if not target_user:
        raise HTTPException(status_code=404, detail="User not found")

    duplicate = await users_collection.find_one(
        {"email": data.new_email, "id": {"$ne": data.user_id}}
    )
    if duplicate:
        raise HTTPException(status_code=400, detail="Email already in use by another user")

    await users_collection.update_one(
        {"id": data.user_id},
        {"$set": {"email": data.new_email, "updated_at": datetime.utcnow()}},
    )

    updated = await users_collection.find_one({"id": data.user_id}, {"hashed_password": 0})
    updated.pop("_id", None)
    return {"message": "Email updated successfully", "user": updated}


# ============================================
# Dashboard Routes
# ============================================

@api_router.get("/dashboard/stats", response_model=DashboardStats)
async def get_dashboard_stats(org_id: str = Depends(get_current_org)):
    """Get dashboard statistics"""
    org_filter = {"organization_id": org_id}
    total_devices = await devices_collection.count_documents(org_filter)
    online_devices = await devices_collection.count_documents({**org_filter, "status": DeviceStatus.ONLINE.value})
    offline_devices = await devices_collection.count_documents({**org_filter, "status": DeviceStatus.OFFLINE.value})
    
    # Recent scans
    recent_scans = await scans_collection.count_documents({
        **org_filter,
        "started_at": {"$gte": datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)}
    })
    
    # Devices by vendor
    pipeline_vendor = [
        {"$match": org_filter},
        {"$group": {"_id": "$vendor", "count": {"$sum": 1}}},
        {"$sort": {"count": -1}},
        {"$limit": 10}
    ]
    vendor_results = await devices_collection.aggregate(pipeline_vendor).to_list(10)
    devices_by_vendor = {item["_id"] or "Unknown": item["count"] for item in vendor_results}
    
    # Devices by type
    pipeline_type = [
        {"$match": org_filter},
        {"$group": {"_id": "$device_type", "count": {"$sum": 1}}},
        {"$sort": {"count": -1}},
        {"$limit": 10}
    ]
    type_results = await devices_collection.aggregate(pipeline_type).to_list(10)
    devices_by_type = {item["_id"] or "Unknown": item["count"] for item in type_results}
    
    return DashboardStats(
        total_devices=total_devices,
        online_devices=online_devices,
        offline_devices=offline_devices,
        recent_scans=recent_scans,
        devices_by_vendor=devices_by_vendor,
        devices_by_type=devices_by_type
    )

# ============================================
# Scanner Routes
# ============================================

async def perform_scan(scan_id: str, subnet: str, scan_ports: bool, check_snmp: bool, 
                       snmp_community: str, user_id: str, org_id: str,
                       custom_ports: list = None, scan_type: str = "discovery",
                       targets: list = None, timeout: int = 2):
    """Background task to perform network scan — devices tagged with org_id and scanned_by user_id"""
    try:
        logger.info(f"Starting scan {scan_id} for subnet {subnet} (type: {scan_type})")
        
        await scans_collection.update_one(
            {"id": scan_id},
            {"$set": {"status": "running"}}
        )
        
        all_devices = []
        
        if targets:
            for target_info in targets:
                target_str = target_info.get("target", subnet)
                target_port = target_info.get("port")
                target_port_range = target_info.get("port_range")
                results = await scanner.scan_target(
                    target_str, port=target_port, port_range=target_port_range,
                    scan_ports=scan_ports, check_snmp=check_snmp,
                    snmp_community=snmp_community, custom_ports=custom_ports,
                    timeout=timeout
                )
                all_devices.extend(results)
        else:
            if ':' in subnet and not '/' in subnet:
                all_devices = await scanner.scan_target(
                    subnet, scan_ports=scan_ports, check_snmp=check_snmp,
                    snmp_community=snmp_community, custom_ports=custom_ports,
                    timeout=timeout
                )
            else:
                all_devices = await scanner.scan_subnet(
                    subnet, scan_ports, check_snmp, snmp_community,
                    custom_ports=custom_ports, timeout=timeout
                )
        
        for device_data in all_devices:
            open_ports_data = device_data.get("open_ports", [])
            open_ports_list = [
                p["port"] if isinstance(p, dict) else p 
                for p in open_ports_data
            ]
            
            existing_device = await devices_collection.find_one(
                {"ip": device_data["ip"], "organization_id": org_id}
            )
            
            if existing_device:
                port_details = []
                if open_ports_data and isinstance(open_ports_data[0], dict):
                    port_details = open_ports_data
                
                update_data = {
                    "status": DeviceStatus.ONLINE.value,
                    "last_seen": datetime.utcnow(),
                    "open_ports": open_ports_list,
                    "port_details": port_details,
                    "snmp_enabled": device_data.get("snmp_enabled", False),
                    "last_scanned_by": user_id,
                    "last_scan_id": scan_id,
                }
                
                if device_data.get("hostname"):
                    update_data["hostname"] = device_data["hostname"]
                if device_data.get("vendor"):
                    update_data["vendor"] = device_data["vendor"]
                if device_data.get("device_type"):
                    update_data["device_type"] = device_data["device_type"]
                if device_data.get("sys_descr"):
                    update_data["sys_descr"] = device_data["sys_descr"]
                
                await devices_collection.update_one(
                    {"ip": device_data["ip"], "organization_id": org_id},
                    {"$set": update_data}
                )
            else:
                device = Device(
                    id=str(uuid.uuid4()),
                    ip=device_data["ip"],
                    hostname=device_data.get("hostname"),
                    vendor=device_data.get("vendor"),
                    device_type=device_data.get("device_type"),
                    status=DeviceStatus.ONLINE,
                    last_seen=datetime.utcnow(),
                    first_discovered=datetime.utcnow(),
                    open_ports=open_ports_list,
                    snmp_enabled=device_data.get("snmp_enabled", False),
                    sys_descr=device_data.get("sys_descr"),
                    created_by=user_id
                )
                device_dict = device.dict()
                device_dict["organization_id"] = org_id
                device_dict["scanned_by"] = user_id
                device_dict["last_scanned_by"] = user_id
                device_dict["last_scan_id"] = scan_id
                device_dict["port_details"] = open_ports_data if open_ports_data and isinstance(open_ports_data[0], dict) else []
                await devices_collection.insert_one(device_dict)
        
        await scans_collection.update_one(
            {"id": scan_id},
            {"$set": {
                "status": "completed",
                "completed_at": datetime.utcnow(),
                "devices_found": len(all_devices)
            }}
        )
        
        logger.info(f"Scan {scan_id} completed. Found {len(all_devices)} devices")
        
    except Exception as e:
        logger.error(f"Scan {scan_id} failed: {e}")
        await scans_collection.update_one(
            {"id": scan_id},
            {"$set": {
                "status": "failed",
                "completed_at": datetime.utcnow(),
                "error": str(e)
            }}
        )

@api_router.post("/scan/start", response_model=ScanResult)
async def start_scan(
    scan_request: ScanRequest,
    background_tasks: BackgroundTasks,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Start a network scan - supports IP, IP:port, CIDR, hostname, ranges"""
    scan = ScanResult(
        id=str(uuid.uuid4()),
        subnet=scan_request.subnet,
        started_at=datetime.utcnow(),
        status="queued",
        created_by=current_user["sub"],
        scan_type=scan_request.scan_type,
        custom_ports=scan_request.custom_ports
    )
    
    scan_dict = scan.dict()
    scan_dict["organization_id"] = org_id
    scan_dict["scanned_by"] = current_user["sub"]
    await scans_collection.insert_one(scan_dict)
    
    targets_data = None
    if scan_request.targets:
        targets_data = [t.dict() for t in scan_request.targets]
    
    background_tasks.add_task(
        perform_scan,
        scan.id,
        scan_request.subnet,
        scan_request.scan_ports,
        scan_request.check_snmp,
        scan_request.snmp_community,
        current_user["sub"],
        org_id,
        scan_request.custom_ports,
        scan_request.scan_type,
        targets_data,
        scan_request.timeout
    )
    
    return scan

@api_router.get("/scan/history", response_model=List[ScanResult])
async def get_scan_history(
    limit: int = 20,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get scan history - admins see all org scans, users see only their own"""
    query = {"organization_id": org_id}
    
    user_doc = await users_collection.find_one({"id": current_user["sub"]})
    user_role = user_doc.get("role", "viewer") if user_doc else "viewer"
    is_org_owner = user_doc.get("is_org_owner", False) if user_doc else False
    
    if user_role not in ("admin", "super_admin") and not is_org_owner:
        query["created_by"] = current_user["sub"]
    
    scans = await scans_collection.find(query).sort("started_at", -1).limit(limit).to_list(limit)
    return [ScanResult(**scan) for scan in scans]

@api_router.get("/scan/{scan_id}", response_model=ScanResult)
async def get_scan_status(scan_id: str, org_id: str = Depends(get_current_org)):
    """Get scan status"""
    scan = await scans_collection.find_one({"id": scan_id, "organization_id": org_id})
    if not scan:
        raise HTTPException(status_code=404, detail="Scan not found")
    
    return ScanResult(**scan)

# ============================================
# Device Routes
# ============================================

@api_router.get("/devices", response_model=List[Device])
async def get_devices(
    status: Optional[str] = None,
    vendor: Optional[str] = None,
    limit: int = 100,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get devices - admins see all org devices, regular users see only their scanned devices"""
    query = {"organization_id": org_id}
    
    user_doc = await users_collection.find_one({"id": current_user["sub"]})
    user_role = user_doc.get("role", "viewer") if user_doc else "viewer"
    is_org_owner = user_doc.get("is_org_owner", False) if user_doc else False
    
    if user_role not in ("admin", "super_admin") and not is_org_owner:
        query["$or"] = [
            {"scanned_by": current_user["sub"]},
            {"created_by": current_user["sub"]},
            {"last_scanned_by": current_user["sub"]}
        ]
    
    if status:
        query["status"] = status
    if vendor:
        query["vendor"] = vendor
    
    devices = await devices_collection.find(query).sort("last_seen", -1).limit(limit).to_list(limit)
    return [Device(**device) for device in devices]

@api_router.get("/devices/{device_id}", response_model=Device)
async def get_device(device_id: str, org_id: str = Depends(get_current_org)):
    """Get device by ID"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    return Device(**device)

class ManualDeviceCreate(BaseModel):
    ip: str
    hostname: Optional[str] = None
    device_type: str = "router"
    vendor: str = "Manual"
    status: str = "unknown"

@api_router.post("/devices/manual")
async def create_manual_device(
    device_data: ManualDeviceCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Manually add a device"""
    existing = await devices_collection.find_one({"ip": device_data.ip, "organization_id": org_id})
    if existing:
        raise HTTPException(status_code=400, detail="Device with this IP already exists")
    
    device_id = str(uuid.uuid4())
    device = {
        "id": device_id,
        "ip": device_data.ip,
        "hostname": device_data.hostname or device_data.ip,
        "device_type": device_data.device_type,
        "vendor": device_data.vendor,
        "status": device_data.status,
        "snmp_enabled": False,
        "open_ports": [],
        "mac_address": None,
        "discovered_at": datetime.utcnow().isoformat(),
        "last_seen": datetime.utcnow().isoformat(),
        "created_by": current_user['sub'],
        "manual_entry": True,
        "organization_id": org_id
    }
    
    await devices_collection.insert_one(device)
    
    return {
        "id": device_id,
        "ip": device_data.ip,
        "hostname": device_data.hostname or device_data.ip,
        "device_type": device_data.device_type,
        "vendor": device_data.vendor,
        "status": device_data.status,
        "message": "Device added successfully"
    }

@api_router.put("/devices/{device_id}", response_model=Device)
async def update_device(
    device_id: str,
    device_update: DeviceUpdate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Update device information"""
    if current_user.get("role") not in [UserRole.ADMIN.value, UserRole.ENGINEER.value]:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    update_data = device_update.dict(exclude_unset=True)
    
    await devices_collection.update_one(
        {"id": device_id, "organization_id": org_id},
        {"$set": update_data}
    )
    
    updated_device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    return Device(**updated_device)

@api_router.delete("/devices/{device_id}")
async def delete_device(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Delete device"""
    if current_user.get("role") != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    result = await devices_collection.delete_one({"id": device_id, "organization_id": org_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Device not found")
    
    return {"message": "Device deleted successfully"}

# ============================================
# SNMP Routes
# ============================================

@api_router.get("/snmp/{device_id}/info", response_model=SNMPData)
async def get_snmp_info(
    device_id: str,
    community: str = "public",
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get SNMP information for a device"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    if not device.get("snmp_enabled"):
        raise HTTPException(status_code=400, detail="SNMP not enabled on this device")
    
    # Use stored community if available
    snmp_community = device.get("snmp_community") or community
    
    # Check SNMP and get data
    snmp_enabled, snmp_data = await scanner.check_snmp(device["ip"], snmp_community)
    
    if not snmp_enabled:
        raise HTTPException(status_code=400, detail="Failed to connect via SNMP")
    
    return SNMPData(**snmp_data) if snmp_data else SNMPData()

# ============================================
# Admin Routes
# ============================================

class UserUpdateStatus(BaseModel):
    is_active: bool

@api_router.get("/admin/users", response_model=List[User])
async def get_all_users(current_user: dict = Depends(get_current_user), org_id: str = Depends(get_current_org)):
    """Get all users (admin only)"""
    if current_user.get("role") != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    users = await users_collection.find({"organization_id": org_id}).sort("created_at", -1).to_list(1000)
    return [User(**user) for user in users]

@api_router.post("/admin/users", response_model=User)
async def create_user_by_admin(user_data: UserCreate, current_user: dict = Depends(get_current_user), org_id: str = Depends(get_current_org)):
    """Create a new user (admin only)"""
    if current_user.get("role") != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    # Check if user already exists
    existing_user = await users_collection.find_one({"email": user_data.email})
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    # Create user
    user = User(
        id=str(uuid.uuid4()),
        email=user_data.email,
        username=user_data.username,
        hashed_password=get_password_hash(user_data.password),
        role=user_data.role or UserRole.VIEWER,
        created_at=datetime.utcnow(),
        is_active=True
    )
    
    user_dict = user.dict()
    user_dict["organization_id"] = org_id
    await users_collection.insert_one(user_dict)
    return user

@api_router.patch("/admin/users/{user_id}")
async def update_user_status(
    user_id: str,
    update_data: UserUpdateStatus,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Update user status (admin only)"""
    if current_user.get("role") != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    # Cannot deactivate self
    if user_id == current_user.get("sub"):
        raise HTTPException(status_code=400, detail="Cannot deactivate yourself")
    
    user = await users_collection.find_one({"id": user_id, "organization_id": org_id})
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    await users_collection.update_one(
        {"id": user_id, "organization_id": org_id},
        {"$set": {"is_active": update_data.is_active}}
    )
    
    return {"message": "User status updated successfully"}

@api_router.delete("/admin/users/{user_id}")
async def delete_user(user_id: str, current_user: dict = Depends(get_current_user), org_id: str = Depends(get_current_org)):
    """Delete user (admin only)"""
    if current_user.get("role") != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    # Cannot delete self
    if user_id == current_user.get("sub"):
        raise HTTPException(status_code=400, detail="Cannot delete yourself")
    
    result = await users_collection.delete_one({"id": user_id, "organization_id": org_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="User not found")
    
    return {"message": "User deleted successfully"}

# ============================================
# Monitoring Routes
# ============================================

class MonitoringRequest(BaseModel):
    device_id: str
    hours: Optional[int] = 24

@api_router.get("/monitoring/metrics/{device_id}")
async def get_device_metrics(
    device_id: str,
    hours: int = 24,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get historical metrics for a device"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    metrics = await monitor.get_device_metrics(device_id, hours)
    return {"device_id": device_id, "metrics": metrics}

@api_router.get("/monitoring/realtime/{device_id}")
async def get_realtime_metrics(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get real-time metrics for a device"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    if not device.get('snmp_enabled'):
        raise HTTPException(status_code=400, detail="SNMP not enabled on this device")
    
    # Get real-time metrics
    ip = device['ip']
    community = device.get('snmp_community', 'public')
    version = device.get('snmp_version', 'v2c')
    
    metrics = await snmp_manager.get_full_device_info(ip, version, community)
    
    return metrics

@api_router.get("/monitoring/bandwidth/{device_id}/{interface}")
async def get_interface_bandwidth(
    device_id: str,
    interface: str,
    hours: int = 1,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get bandwidth usage for an interface"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    bandwidth = await monitor.get_interface_bandwidth(device_id, interface, hours)
    return bandwidth

@api_router.get("/alerts")
async def get_alerts(
    acknowledged: Optional[bool] = None,
    severity: Optional[str] = None,
    limit: int = 100,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get system alerts"""
    query = {"organization_id": org_id}
    if acknowledged is not None:
        query['acknowledged'] = acknowledged
    if severity:
        query['severity'] = severity
    
    alerts = await alerts_collection.find(query).sort("timestamp", -1).limit(limit).to_list(limit)
    return alerts

@api_router.patch("/alerts/{alert_id}/acknowledge")
async def acknowledge_alert(
    alert_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Acknowledge an alert"""
    result = await alerts_collection.update_one(
        {"_id": alert_id, "organization_id": org_id},
        {"$set": {"acknowledged": True, "acknowledged_by": current_user['sub'], "acknowledged_at": datetime.utcnow()}}
    )
    
    if result.modified_count == 0:
        raise HTTPException(status_code=404, detail="Alert not found")
    
    return {"message": "Alert acknowledged"}

@api_router.delete("/alerts/{alert_id}")
async def delete_alert(
    alert_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Delete an alert"""
    if current_user.get("role") not in [UserRole.ADMIN.value, UserRole.ENGINEER.value]:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    result = await alerts_collection.delete_one({"_id": alert_id, "organization_id": org_id})
    
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Alert not found")
    
    return {"message": "Alert deleted"}

# ============================================
# Advanced SNMP Routes
# ============================================

class SNMPGetRequest(BaseModel):
    ip: str
    oid: str
    version: str = 'v2c'
    community: str = 'public'
    port: int = 161

class SNMPWalkRequest(BaseModel):
    ip: str
    oid: str
    version: str = 'v2c'
    community: str = 'public'
    port: int = 161

@api_router.post("/snmp/get")
async def snmp_get(
    request: SNMPGetRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Perform SNMP GET operation"""
    success, value = await snmp_manager.get(
        request.ip,
        request.oid,
        request.version,
        request.community,
        request.port
    )
    
    if not success:
        raise HTTPException(status_code=400, detail="SNMP GET failed")
    
    return {"oid": request.oid, "value": value}

@api_router.post("/snmp/walk")
async def snmp_walk(
    request: SNMPWalkRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Perform SNMP WALK operation"""
    results = await snmp_manager.walk(
        request.ip,
        request.oid,
        request.version,
        request.community,
        request.port
    )
    
    return {"oid": request.oid, "results": [{"oid": oid, "value": value} for oid, value in results]}

@api_router.get("/snmp/system/{device_id}")
async def get_snmp_system_info(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get SNMP system information"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    if not device.get('snmp_enabled'):
        raise HTTPException(status_code=400, detail="SNMP not enabled")
    
    system_info = await snmp_manager.get_system_info(
        device['ip'],
        device.get('snmp_version', 'v2c'),
        device.get('snmp_community', 'public')
    )
    
    return system_info

@api_router.get("/snmp/interfaces/{device_id}")
async def get_snmp_interfaces(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get device interfaces via SNMP"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    if not device.get('snmp_enabled'):
        raise HTTPException(status_code=400, detail="SNMP not enabled")
    
    interfaces = await snmp_manager.get_interfaces(
        device['ip'],
        device.get('snmp_version', 'v2c'),
        device.get('snmp_community', 'public')
    )
    
    return {"device_id": device_id, "interfaces": interfaces}

# ============================================
# LLDP/CDP Discovery Routes
# ============================================

@api_router.get("/discovery/neighbors/{device_id}")
async def discover_neighbors(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Discover LLDP/CDP neighbors for a device"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    if not device.get('snmp_enabled'):
        raise HTTPException(status_code=400, detail="SNMP not enabled")
    
    neighbors = await lldp_cdp_discovery.discover_all_neighbors(
        device['ip'],
        device.get('snmp_community', 'public')
    )
    
    # Save neighbors to device
    await devices_collection.update_one(
        {"id": device_id},
        {"$set": {"neighbors": neighbors, "neighbors_updated_at": datetime.utcnow()}}
    )
    
    return neighbors

# ============================================
# MikroTik Routes
# ============================================

class MikroTikCredentials(BaseModel):
    username: str
    password: str

@api_router.post("/mikrotik/{device_id}/resource")
async def get_mikrotik_resource(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get MikroTik system resources"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        resource = mikrotik_manager.get_system_resource(
            device['ip'], credentials.username, credentials.password
        )
        return resource
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/mikrotik/{device_id}/interfaces")
async def get_mikrotik_interfaces(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get MikroTik interfaces"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        interfaces = mikrotik_manager.get_interfaces(
            device['ip'], credentials.username, credentials.password
        )
        return {"device_id": device_id, "interfaces": interfaces}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/mikrotik/{device_id}/dhcp-leases")
async def get_mikrotik_dhcp_leases(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get MikroTik DHCP leases"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        leases = mikrotik_manager.get_dhcp_server_leases(
            device['ip'], credentials.username, credentials.password
        )
        return {"device_id": device_id, "leases": leases}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/mikrotik/{device_id}/pppoe")
async def get_mikrotik_pppoe(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get MikroTik PPPoE active sessions"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        sessions = mikrotik_manager.get_pppoe_active(
            device['ip'], credentials.username, credentials.password
        )
        return {"device_id": device_id, "sessions": sessions}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/mikrotik/{device_id}/queues")
async def get_mikrotik_queues(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get MikroTik simple queues"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        queues = mikrotik_manager.get_queue_simple(
            device['ip'], credentials.username, credentials.password
        )
        return {"device_id": device_id, "queues": queues}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/mikrotik/{device_id}/firewall")
async def get_mikrotik_firewall(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get MikroTik firewall rules"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        rules = mikrotik_manager.get_firewall_filter(
            device['ip'], credentials.username, credentials.password
        )
        return {"device_id": device_id, "rules": rules}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/mikrotik/{device_id}/backup")
async def create_mikrotik_backup(
    device_id: str,
    credentials: MikroTikCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create MikroTik backup"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        backup = mikrotik_manager.create_backup(
            device['ip'], credentials.username, credentials.password
        )
        return backup
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# ============================================
# Cisco SSH Routes
# ============================================

class SSHCredentials(BaseModel):
    username: str
    password: str
    enable_secret: Optional[str] = None
    device_type: str = 'ios'

@api_router.post("/cisco/{device_id}/version")
async def get_cisco_version(
    device_id: str,
    credentials: SSHCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get Cisco device version"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        version = cisco_ssh_manager.get_version(
            device['ip'], credentials.username, credentials.password,
            credentials.device_type, credentials.enable_secret
        )
        return version
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/cisco/{device_id}/interfaces")
async def get_cisco_interfaces(
    device_id: str,
    credentials: SSHCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get Cisco interfaces"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        interfaces = cisco_ssh_manager.get_interfaces(
            device['ip'], credentials.username, credentials.password,
            credentials.device_type, credentials.enable_secret
        )
        return {"device_id": device_id, "interfaces": interfaces}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/cisco/{device_id}/backup")
async def backup_cisco_config(
    device_id: str,
    credentials: SSHCredentials,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Backup Cisco configuration"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        config = cisco_ssh_manager.backup_config(
            device['ip'], credentials.username, credentials.password,
            credentials.device_type, credentials.enable_secret
        )
        
        # Save backup to database
        backup_doc = {
            'device_id': device_id,
            'ip': device['ip'],
            'config': config,
            'timestamp': datetime.utcnow(),
            'created_by': current_user['sub'],
            'organization_id': org_id
        }
        await db.backups.insert_one(backup_doc)
        
        return {"success": True, "size": len(config)}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# ============================================
# Huawei OLT Routes
# ============================================

@api_router.post("/huawei/{device_id}/onu-list")
async def get_huawei_onu_list(
    device_id: str,
    credentials: SSHCredentials,
    frame: int = 0,
    slot: int = 0,
    port: int = 0,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get Huawei ONU list"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        onus = huawei_olt.get_onu_list(
            device['ip'], credentials.username, credentials.password,
            frame, slot, port
        )
        return {"device_id": device_id, "frame": frame, "slot": slot, "port": port, "onus": onus}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/huawei/{device_id}/onu-optical/{ont_id}")
async def get_huawei_onu_optical(
    device_id: str,
    ont_id: int,
    credentials: SSHCredentials,
    frame: int = 0,
    slot: int = 0,
    port: int = 0,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get Huawei ONU optical information"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        optical_info = huawei_olt.get_onu_optical_info(
            device['ip'], credentials.username, credentials.password,
            frame, slot, port, ont_id
        )
        return {"device_id": device_id, "ont_id": ont_id, "optical_info": optical_info}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/huawei/{device_id}/onu-add")
async def add_huawei_onu(
    device_id: str,
    credentials: SSHCredentials,
    frame: int,
    slot: int,
    port: int,
    ont_id: int,
    sn: str,
    profile_id: int = 1,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Add/Register Huawei ONU"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    # Check permission
    if current_user.get("role") not in [UserRole.ADMIN.value, UserRole.ENGINEER.value]:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    try:
        result = huawei_olt.add_onu(
            device['ip'], credentials.username, credentials.password,
            frame, slot, port, ont_id, sn, profile_id
        )
        return {"success": True, "result": result}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/huawei/{device_id}/onu-reboot/{ont_id}")
async def reboot_huawei_onu(
    device_id: str,
    ont_id: int,
    credentials: SSHCredentials,
    frame: int = 0,
    slot: int = 0,
    port: int = 0,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Reboot Huawei ONU"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    # Check permission
    if current_user.get("role") not in [UserRole.ADMIN.value, UserRole.ENGINEER.value]:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    try:
        result = huawei_olt.reboot_onu(
            device['ip'], credentials.username, credentials.password,
            frame, slot, port, ont_id
        )
        return {"success": True, "result": result}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# ============================================
# Topology Routes
# ============================================

@api_router.get("/topology")
async def get_network_topology(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get network topology scoped to organization"""
    topology = await topology_builder.build_topology(org_id)
    return topology

# ============================================
# Reports Routes
# ============================================

@api_router.get("/reports/daily")
async def get_daily_report(
    date: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get daily report"""
    report_date = datetime.fromisoformat(date) if date else None
    report = await reports_engine.generate_daily_report(report_date, org_id)
    return report

@api_router.get("/reports/weekly")
async def get_weekly_report(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get weekly report"""
    report = await reports_engine.generate_weekly_report(org_id=org_id)
    return report

@api_router.get("/reports/device/{device_id}")
async def get_device_report(
    device_id: str,
    days: int = 30,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get device report"""
    report = await reports_engine.generate_device_report(device_id, days, org_id)
    return report

@api_router.get("/reports/vendor")
async def get_vendor_report(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get vendor distribution report"""
    report = await reports_engine.generate_vendor_report(org_id)
    return report

# ============================================
# Backup Routes
# ============================================

@api_router.get("/backups/{device_id}")
async def get_device_backups(
    device_id: str,
    limit: int = 50,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get backup history"""
    backups = await backup_manager.get_backups(device_id, limit, org_id)
    return {"device_id": device_id, "backups": backups}

@api_router.get("/backups/detail/{backup_id}")
async def get_backup_detail(
    backup_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get backup details"""
    backup = await backup_manager.get_backup(backup_id, org_id)
    if not backup:
        raise HTTPException(status_code=404, detail="Backup not found")
    return backup

@api_router.post("/backups/{device_id}/compare")
async def compare_device_backups(
    device_id: str,
    backup_id1: str,
    backup_id2: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Compare two backups scoped to organization"""
    try:
        comparison = await backup_manager.compare_backups(backup_id1, backup_id2, org_id)
        return comparison
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# ============================================
# Firmware Routes
# ============================================

@api_router.get("/firmware/check/{device_id}")
async def check_firmware_update(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Check firmware updates"""
    try:
        result = await firmware_manager.check_firmware_updates(device_id, org_id)
        return result
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.get("/firmware/outdated")
async def get_outdated_devices(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get devices with outdated firmware"""
    devices = await firmware_manager.get_devices_with_outdated_firmware(org_id)
    return {"count": len(devices), "devices": devices}

# ============================================
# Asset Management Routes
# ============================================

class AssetCreate(BaseModel):
    asset_tag: Optional[str] = None
    serial_number: Optional[str] = None
    model_number: Optional[str] = None
    manufacturer: Optional[str] = None
    purchase_date: Optional[datetime] = None
    purchase_price: Optional[float] = None
    warranty_expires: Optional[datetime] = None
    location: Optional[str] = None
    department: Optional[str] = None
    owner: Optional[str] = None
    notes: Optional[str] = None

@api_router.post("/assets/{device_id}")
async def create_device_asset(
    device_id: str,
    asset_data: AssetCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create asset record"""
    if current_user.get("role") not in [UserRole.ADMIN.value, UserRole.ENGINEER.value]:
        raise HTTPException(status_code=403, detail="Not enough permissions")
    
    try:
        asset = await asset_manager.create_asset(device_id, asset_data.dict(), org_id)
        return asset
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.get("/assets/device/{device_id}")
async def get_device_asset_info(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get asset information for device"""
    asset = await asset_manager.get_device_asset(device_id, org_id)
    if not asset:
        raise HTTPException(status_code=404, detail="Asset not found")
    return asset

@api_router.get("/assets/warranty-expiring")
async def get_warranty_expiring(
    days: int = 90,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get assets with warranty expiring soon"""
    assets = await asset_manager.get_warranty_expiring(days, org_id)
    return {"count": len(assets), "assets": assets}

@api_router.get("/assets/inventory")
async def get_inventory_report(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get inventory report"""
    report = await asset_manager.generate_inventory_report(org_id)
    return report

# ============================================
# Universal Device Manager Routes (Phase 12)
# ============================================

class UniversalDeviceCommand(BaseModel):
    username: str
    password: str
    command: str
    vendor: str = 'generic'

@api_router.post("/universal/{device_id}/execute")
async def universal_execute_command(
    device_id: str,
    request: UniversalDeviceCommand,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Execute command on any vendor device"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        output = await universal_device_manager.execute_command(
            device['ip'], request.username, request.password,
            request.command, request.vendor
        )
        return {"device_id": device_id, "output": output}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@api_router.post("/universal/{device_id}/backup")
async def universal_backup_config(
    device_id: str,
    request: UniversalDeviceCommand,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Backup config from any vendor device"""
    device = await devices_collection.find_one({"id": device_id, "organization_id": org_id})
    if not device:
        raise HTTPException(status_code=404, detail="Device not found")
    
    try:
        config = await universal_device_manager.backup_config(
            device['ip'], request.username, request.password, request.vendor
        )
        
        # Save backup
        backup_doc = {
            'id': str(uuid.uuid4()),
            'device_id': device_id,
            'config': config,
            'vendor': request.vendor,
            'timestamp': datetime.utcnow(),
            'created_by': current_user['sub'],
            'organization_id': org_id
        }
        await db.config_backups.insert_one(backup_doc)
        
        return {"success": True, "backup_id": backup_doc['id'], "size": len(config)}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# ============================================
# Traffic Analysis Routes (Phase 13)
# ============================================

class NetFlowData(BaseModel):
    src_ip: str
    dst_ip: str
    src_port: int
    dst_port: int
    protocol: int
    bytes: int
    packets: int
    exporter_ip: Optional[str] = None

@api_router.post("/traffic/netflow")
async def receive_netflow(
    flow_data: NetFlowData,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Receive NetFlow data"""
    data = flow_data.dict()
    data["organization_id"] = org_id
    await traffic_analyzer.process_netflow_packet(data)
    return {"status": "processed"}

@api_router.get("/traffic/top-talkers")
async def get_top_talkers(
    device_id: Optional[str] = None,
    hours: int = 1,
    limit: int = 10,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get top bandwidth consumers"""
    talkers = await traffic_analyzer.get_top_talkers(device_id, hours, limit, org_id)
    return {"top_talkers": talkers}

@api_router.get("/traffic/top-applications")
async def get_top_applications(
    hours: int = 1,
    limit: int = 10,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get top applications by traffic"""
    apps = await traffic_analyzer.get_top_applications(hours, limit, org_id)
    return {"applications": apps}

@api_router.get("/traffic/protocols")
async def get_traffic_by_protocol(
    hours: int = 1,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get traffic breakdown by protocol"""
    protocols = await traffic_analyzer.get_top_protocols(hours, org_id)
    return {"protocols": protocols}

@api_router.get("/traffic/timeline")
async def get_traffic_timeline(
    hours: int = 24,
    interval: int = 30,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get traffic over time"""
    timeline = await traffic_analyzer.get_traffic_timeline(hours, interval, org_id)
    return {"timeline": timeline}

@api_router.get("/traffic/conversations")
async def get_conversation_pairs(
    hours: int = 1,
    limit: int = 20,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get top conversation pairs"""
    conversations = await traffic_analyzer.get_conversation_pairs(hours, limit, org_id)
    return {"conversations": conversations}

@api_router.get("/traffic/device/{device_id}")
async def get_device_traffic_analysis(
    device_id: str,
    hours: int = 24,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get comprehensive traffic analysis for device"""
    analysis = await traffic_analyzer.analyze_bandwidth_usage(device_id, hours, org_id)
    return analysis

# ============================================
# AI Configuration Engine Routes (Phase 14)
# ============================================

class AIConfigRequest(BaseModel):
    requirements: str

class ConfigGenerateRequest(BaseModel):
    vendor: str
    device_type: str
    hostname: str
    management_ip: str

class VLANConfigRequest(BaseModel):
    vendor: str
    vlan_id: int
    vlan_name: str
    ports: List[str]

class DHCPConfigRequest(BaseModel):
    vendor: str
    pool_name: str
    network: str
    gateway: str
    dns: List[str]

class ConfigValidateRequest(BaseModel):
    config: str
    vendor: str

@api_router.get("/ai/capabilities/{device_id}")
async def get_device_capabilities(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Auto-detect device capabilities"""
    capabilities = await ai_config_engine.auto_detect_device_capabilities(device_id, org_id)
    return capabilities

@api_router.post("/ai/generate-config")
async def generate_basic_config(
    request: ConfigGenerateRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Generate basic device configuration"""
    config = ai_config_engine.generate_basic_config(
        request.vendor, request.device_type,
        request.hostname, request.management_ip
    )
    return {"config": config, "vendor": request.vendor}

@api_router.post("/ai/generate-config/{device_id}")
async def ai_generate_device_config(
    device_id: str,
    request: AIConfigRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Use AI to generate configuration based on requirements"""
    result = await ai_config_engine.ai_generate_config(device_id, request.requirements, org_id)
    return result

@api_router.post("/ai/generate-vlan")
async def generate_vlan_config(
    request: VLANConfigRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Generate VLAN configuration"""
    config = await ai_config_engine.generate_vlan_config(
        request.vendor, request.vlan_id,
        request.vlan_name, request.ports
    )
    return {"config": config, "vlan_id": request.vlan_id}

@api_router.post("/ai/generate-dhcp")
async def generate_dhcp_config(
    request: DHCPConfigRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Generate DHCP configuration"""
    config = await ai_config_engine.generate_dhcp_config(
        request.vendor, request.pool_name,
        request.network, request.gateway, request.dns
    )
    return {"config": config, "pool_name": request.pool_name}

@api_router.get("/ai/suggest/{device_id}")
async def get_ai_suggestions(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get AI-powered optimization suggestions"""
    suggestions = await ai_config_engine.ai_suggest_optimization(device_id, org_id)
    return suggestions

@api_router.post("/ai/explain-config")
async def explain_config(
    request: ConfigValidateRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Use AI to explain a configuration"""
    explanation = await ai_config_engine.ai_explain_config(request.config, request.vendor)
    return explanation

@api_router.post("/ai/optimize-config")
async def optimize_config(
    request: ConfigValidateRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Use AI to optimize a configuration"""
    result = await ai_config_engine.ai_optimize_config(request.config, request.vendor)
    return result

@api_router.post("/ai/validate-config")
async def validate_config(
    request: ConfigValidateRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Validate configuration syntax"""
    validation = await ai_config_engine.validate_config(request.config, request.vendor)
    return validation

# ============================================
# AI Troubleshooter Routes (Phase 15)
# ============================================

class TroubleshootRequest(BaseModel):
    issue_description: str

class LogAnalyzeRequest(BaseModel):
    logs: str

@api_router.get("/troubleshoot/health/{device_id}")
async def get_device_health(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get comprehensive device health analysis"""
    health = await ai_troubleshooter.analyze_device_health(device_id, org_id)
    return health

@api_router.post("/troubleshoot/diagnose/{device_id}")
async def troubleshoot_device(
    device_id: str,
    request: TroubleshootRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """AI-powered troubleshooting for specific issue"""
    result = await ai_troubleshooter.troubleshoot_issue(device_id, request.issue_description, org_id)
    return result

@api_router.post("/troubleshoot/analyze-logs/{device_id}")
async def analyze_device_logs(
    device_id: str,
    request: LogAnalyzeRequest,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """AI-powered log analysis"""
    analysis = await ai_troubleshooter.ai_analyze_logs(device_id, request.logs, org_id)
    return analysis

@api_router.get("/troubleshoot/network-health")
async def get_network_health_summary(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get overall network health summary"""
    summary = await ai_troubleshooter.get_network_health_summary(org_id)
    return summary

@api_router.get("/troubleshoot/predict/{device_id}")
async def predict_device_issues(
    device_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Predict potential issues based on trends"""
    predictions = await ai_troubleshooter.predict_issues(device_id, org_id)
    return predictions

# ============================================
# Admin Panel Routes (Super Admin & Admin)
# ============================================

# Pydantic Models for Admin Panel
class OrganizationCreate(BaseModel):
    name: str
    domain: Optional[str] = None
    plan: str = "free"

class OrganizationUpdate(BaseModel):
    name: Optional[str] = None
    domain: Optional[str] = None
    logo_url: Optional[str] = None
    front_image_url: Optional[str] = None
    primary_color: Optional[str] = None

class FeatureToggle(BaseModel):
    feature: str
    enabled: bool

class UserApproval(BaseModel):
    status: str  # approved, rejected
    reason: Optional[str] = None

class APISettingCreate(BaseModel):
    name: str
    api_key: str
    provider: str = "openai"

class SupportTicketCreate(BaseModel):
    subject: str
    description: str
    priority: str = "medium"
    category: str = "general"

class TicketMessageCreate(BaseModel):
    message: str

class MapMarkerCreate(BaseModel):
    name: str
    latitude: float
    longitude: float
    device_id: Optional[str] = None
    marker_type: str = "device"
    color: str = "#3b82f6"

class UserSettingsUpdate(BaseModel):
    theme: Optional[str] = None
    language: Optional[str] = None
    notifications_enabled: Optional[bool] = None
    email_notifications: Optional[bool] = None

class ProfileUpdate(BaseModel):
    username: Optional[str] = None
    phone: Optional[str] = None
    avatar_url: Optional[str] = None
    timezone: Optional[str] = None

# Organization Management
@api_router.post("/panel/organization")
async def create_organization(
    org_data: OrganizationCreate,
    current_user: dict = Depends(get_current_user)
):
    """Create a new organization (first org makes user owner)"""
    org = await admin_manager.create_organization(
        org_data.name, current_user['sub'],
        org_data.domain, org_data.plan
    )
    return org

@api_router.get("/panel/organization")
async def get_my_organization(current_user: dict = Depends(get_current_user)):
    """Get current user's organization"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        return {"organization": None}
    
    org = await admin_manager.get_organization(user['organization_id'])
    return org

@api_router.put("/panel/organization")
async def update_organization(
    updates: OrganizationUpdate,
    current_user: dict = Depends(get_current_user)
):
    """Update organization settings"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    org = await admin_manager.update_organization(
        user['organization_id'], updates.dict(exclude_unset=True)
    )
    return org

@api_router.put("/panel/organization/branding")
async def update_branding(
    updates: OrganizationUpdate,
    current_user: dict = Depends(get_current_user)
):
    """Update organization branding (logo, colors, etc.)"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    org = await admin_manager.update_branding(
        user['organization_id'],
        updates.logo_url, updates.front_image_url,
        updates.primary_color, updates.name
    )
    return org

@api_router.post("/panel/organization/regenerate-api-key")
async def regenerate_org_api_key(current_user: dict = Depends(get_current_user)):
    """Regenerate organization API key"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    new_key = await admin_manager.regenerate_api_key(user['organization_id'])
    return {"api_key": new_key}

# Feature Toggles
@api_router.get("/panel/features")
async def get_features(current_user: dict = Depends(get_current_user)):
    """Get organization features"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        # Return default features for users without org
        return {"features_enabled": admin_manager._get_default_features('free')}
    
    org = await admin_manager.get_organization(user['organization_id'])
    return {"features_enabled": org.get('features_enabled', {})}

@api_router.put("/panel/features")
async def update_features(
    features: dict,
    current_user: dict = Depends(get_current_user)
):
    """Update all feature toggles"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    org = await admin_manager.update_features(user['organization_id'], features)
    return {"features_enabled": org.get('features_enabled', {})}

@api_router.patch("/panel/features/{feature}")
async def toggle_feature(
    feature: str,
    toggle: FeatureToggle,
    current_user: dict = Depends(get_current_user)
):
    """Toggle single feature"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    await admin_manager.toggle_feature(
        user['organization_id'], feature, toggle.enabled
    )
    return {"feature": feature, "enabled": toggle.enabled}

# User Approval System
@api_router.get("/panel/users/pending")
async def get_pending_users(current_user: dict = Depends(get_current_user)):
    """Get pending user registrations"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    org_id = user.get('organization_id') if user else None
    
    pending = await admin_manager.get_pending_users(org_id)
    return {"pending_users": pending}

@api_router.post("/panel/users/{user_id}/approve")
async def approve_user(
    user_id: str,
    current_user: dict = Depends(get_current_user)
):
    """Approve user registration"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await admin_manager.approve_user(user_id, current_user['sub'])
    return {"success": True, "user": user}

@api_router.post("/panel/users/{user_id}/reject")
async def reject_user(
    user_id: str,
    data: UserApproval,
    current_user: dict = Depends(get_current_user)
):
    """Reject user registration"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await admin_manager.reject_user(user_id, current_user['sub'], data.reason)
    return {"success": True, "user": user}

@api_router.post("/panel/users/{user_id}/suspend")
async def suspend_user(
    user_id: str,
    data: UserApproval,
    current_user: dict = Depends(get_current_user)
):
    """Suspend user account"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await admin_manager.suspend_user(user_id, current_user['sub'], data.reason)
    return {"success": True, "user": user}

# API Settings
@api_router.get("/panel/api-settings")
async def get_api_settings(current_user: dict = Depends(get_current_user)):
    """Get API settings"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        return {"api_settings": []}
    
    settings = await admin_manager.get_api_settings(user['organization_id'])
    return {"api_settings": settings}

@api_router.post("/panel/api-settings")
async def create_api_setting(
    data: APISettingCreate,
    current_user: dict = Depends(get_current_user)
):
    """Create API setting"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    setting = await admin_manager.create_api_setting(
        user['organization_id'], data.name, data.api_key, data.provider
    )
    return setting

@api_router.delete("/panel/api-settings/{setting_id}")
async def delete_api_setting(
    setting_id: str,
    current_user: dict = Depends(get_current_user)
):
    """Delete API setting"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    success = await admin_manager.delete_api_setting(setting_id)
    if not success:
        raise HTTPException(status_code=404, detail="Setting not found")
    
    return {"success": True}

@api_router.get("/panel/generate-api-key")
async def generate_new_api_key(current_user: dict = Depends(get_current_user)):
    """Generate a new random API key"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    key = await admin_manager.generate_api_key()
    return {"api_key": key}

# Support Tickets
@api_router.post("/panel/support/tickets")
async def create_support_ticket(
    data: SupportTicketCreate,
    current_user: dict = Depends(get_current_user)
):
    """Create support ticket"""
    user = await users_collection.find_one({'id': current_user['sub']})
    org_id = user.get('organization_id') if user else None
    
    ticket = await admin_manager.create_ticket(
        org_id, current_user['sub'], current_user.get('email', ''),
        data.subject, data.description, data.priority, data.category
    )
    return ticket

@api_router.get("/panel/support/tickets")
async def get_support_tickets(
    status: Optional[str] = None,
    current_user: dict = Depends(get_current_user)
):
    """Get support tickets"""
    user = await users_collection.find_one({'id': current_user['sub']})
    org_id = user.get('organization_id') if user else None
    
    # Admins see all tickets, users see only their own
    if current_user.get('role') == UserRole.ADMIN.value:
        tickets = await admin_manager.get_tickets(org_id=org_id, status=status)
    else:
        tickets = await admin_manager.get_tickets(user_id=current_user['sub'], status=status)
    
    return {"tickets": tickets}

@api_router.get("/panel/support/tickets/{ticket_id}")
async def get_support_ticket(
    ticket_id: str,
    current_user: dict = Depends(get_current_user)
):
    """Get single ticket"""
    ticket = await admin_manager.get_ticket(ticket_id)
    if not ticket:
        raise HTTPException(status_code=404, detail="Ticket not found")
    
    # Check access
    if current_user.get('role') != UserRole.ADMIN.value and ticket['user_id'] != current_user['sub']:
        raise HTTPException(status_code=403, detail="Access denied")
    
    return ticket

@api_router.post("/panel/support/tickets/{ticket_id}/message")
async def add_ticket_message(
    ticket_id: str,
    data: TicketMessageCreate,
    current_user: dict = Depends(get_current_user)
):
    """Add message to ticket"""
    is_admin = current_user.get('role') == UserRole.ADMIN.value
    
    ticket = await admin_manager.add_ticket_message(
        ticket_id, data.message, current_user['sub'], is_admin
    )
    return ticket

@api_router.patch("/panel/support/tickets/{ticket_id}/status")
async def update_ticket_status(
    ticket_id: str,
    status: str,
    current_user: dict = Depends(get_current_user)
):
    """Update ticket status (admin only)"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    ticket = await admin_manager.update_ticket_status(
        ticket_id, status, current_user['sub']
    )
    return ticket

# Login Logs
@api_router.get("/panel/login-logs")
async def get_login_logs(
    limit: int = 100,
    current_user: dict = Depends(get_current_user)
):
    """Get login logs"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    org_id = user.get('organization_id') if user else None
    
    logs = await admin_manager.get_login_logs(org_id=org_id, limit=limit)
    return {"login_logs": logs}

# User Settings & Profile
@api_router.get("/panel/settings")
async def get_user_settings(current_user: dict = Depends(get_current_user)):
    """Get user settings"""
    settings = await admin_manager.get_user_settings(current_user['sub'])
    return settings

@api_router.put("/panel/settings")
async def update_user_settings(
    data: UserSettingsUpdate,
    current_user: dict = Depends(get_current_user)
):
    """Update user settings"""
    settings = await admin_manager.update_user_settings(
        current_user['sub'], data.dict(exclude_unset=True)
    )
    return settings

@api_router.put("/panel/profile")
async def update_profile(
    data: ProfileUpdate,
    current_user: dict = Depends(get_current_user)
):
    """Update user profile"""
    user = await admin_manager.update_profile(
        current_user['sub'], data.dict(exclude_unset=True)
    )
    return user

# Billing
@api_router.get("/panel/billing/plans")
async def get_billing_plans(current_user: dict = Depends(get_current_user)):
    """Get available billing plans"""
    plans = await admin_manager.get_billing_plans()
    return {"plans": plans}

@api_router.get("/panel/billing/subscription")
async def get_subscription(current_user: dict = Depends(get_current_user)):
    """Get current subscription"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        return {"subscription": None}
    
    sub = await admin_manager.get_subscription(user['organization_id'])
    return {"subscription": sub}

@api_router.post("/panel/billing/subscribe/{plan_type}")
async def subscribe_to_plan(
    plan_type: str,
    annual: bool = False,
    current_user: dict = Depends(get_current_user)
):
    """Subscribe to a plan"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    sub = await admin_manager.create_subscription(
        user['organization_id'], plan_type, annual
    )
    return sub

@api_router.get("/panel/billing/invoices")
async def get_invoices(current_user: dict = Depends(get_current_user)):
    """Get invoices"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        return {"invoices": []}
    
    invoices = await admin_manager.get_invoices(user['organization_id'])
    return {"invoices": invoices}

# Map
@api_router.get("/panel/map/markers")
async def get_map_markers(current_user: dict = Depends(get_current_user)):
    """Get map markers"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        return {"markers": []}
    
    markers = await admin_manager.get_map_markers(user['organization_id'])
    return {"markers": markers}

@api_router.post("/panel/map/markers")
async def create_map_marker(
    data: MapMarkerCreate,
    current_user: dict = Depends(get_current_user)
):
    """Create map marker"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    marker = await admin_manager.add_map_marker(
        user['organization_id'], data.name,
        data.latitude, data.longitude,
        data.device_id, data.marker_type, data.color
    )
    return marker

@api_router.put("/panel/map/markers/{marker_id}")
async def update_map_marker(
    marker_id: str,
    data: MapMarkerCreate,
    current_user: dict = Depends(get_current_user)
):
    """Update map marker"""
    marker = await admin_manager.update_map_marker(
        marker_id, data.dict(exclude_unset=True)
    )
    return marker

@api_router.delete("/panel/map/markers/{marker_id}")
async def delete_map_marker(
    marker_id: str,
    current_user: dict = Depends(get_current_user)
):
    """Delete map marker"""
    success = await admin_manager.delete_map_marker(marker_id)
    if not success:
        raise HTTPException(status_code=404, detail="Marker not found")
    return {"success": True}

@api_router.get("/panel/map/settings")
async def get_map_settings(current_user: dict = Depends(get_current_user)):
    """Get map settings"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        return {"default_center": {"lat": 0, "lng": 0}, "default_zoom": 10}
    
    settings = await admin_manager.get_map_settings(user['organization_id'])
    return settings

@api_router.put("/panel/map/settings")
async def update_map_settings(
    settings: dict,
    current_user: dict = Depends(get_current_user)
):
    """Update map settings"""
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('organization_id'):
        raise HTTPException(status_code=404, detail="No organization found")
    
    updated = await admin_manager.update_map_settings(
        user['organization_id'], settings
    )
    return updated


# ==================== GIS NETWORK MAP APIs ====================

# GIS Collections
gis_cables_collection = db.gis_cables
gis_junctions_collection = db.gis_junctions
gis_fibers_collection = db.gis_fibers
gis_incidents_collection = db.gis_incidents
gis_routes_collection = db.gis_routes

# GIS Pydantic Models

# Extended Cable Types
GIS_CABLE_TYPES = [
    "fiber_sm", "fiber_mm", "fiber_aerial", "fiber_underground", "fiber_submarine", "fiber_drop",
    "copper_cat5", "copper_cat6", "copper_coax", "hybrid", "planned", "under_construction"
]

# Extended Junction Types  
GIS_JUNCTION_TYPES = [
    "splice", "patch_panel", "pole", "cabinet", "building", "manhole",
    "olt", "onu", "splitter", "fdt", "fat", "joint_closure", 
    "handhole", "pedestal", "tower", "data_center", "pop", "customer"
]

# Incident Types
GIS_INCIDENT_TYPES = [
    "fiber_cut", "damage", "maintenance", "outage", 
    "degradation", "theft", "weather", "accident"
]

class GISCableCreate(BaseModel):
    name: str
    cable_type: str = "fiber_sm"
    fiber_count: int = 12
    color: str = "#3b82f6"
    path: list  # Array of {lat, lng} coordinates
    start_junction_id: Optional[str] = None
    end_junction_id: Optional[str] = None
    length_km: Optional[float] = None
    loss_per_km: float = 0.35  # dB/km
    notes: Optional[str] = None

class GISJunctionCreate(BaseModel):
    name: str
    junction_type: str = "splice"
    latitude: float
    longitude: float
    elevation: Optional[float] = None
    splice_loss: float = 0.1  # dB
    devices: list = []  # Device IDs at this junction
    notes: Optional[str] = None
    icon: str = "location"

class GISIncidentCreate(BaseModel):
    title: str
    incident_type: str = "fiber_cut"
    severity: str = "medium"  # low, medium, high, critical
    latitude: float
    longitude: float
    cable_id: Optional[str] = None
    junction_id: Optional[str] = None
    description: Optional[str] = None
    status: str = "open"  # open, in_progress, resolved

class GISFiberCreate(BaseModel):
    cable_id: str
    fiber_number: int
    color: str = "blue"
    status: str = "active"  # active, spare, faulty, reserved
    wavelength: Optional[str] = None
    customer_id: Optional[str] = None
    notes: Optional[str] = None

# GIS Cables CRUD
@api_router.get("/gis/cables")
async def get_gis_cables(
    cable_type: Optional[str] = None,
    limit: int = 500,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get all GIS cables"""
    query = {"organization_id": org_id}
    if cable_type:
        query["cable_type"] = cable_type
    
    cables = await gis_cables_collection.find(query).limit(limit).to_list(limit)
    # Convert ObjectId to string
    for cable in cables:
        cable["_id"] = str(cable["_id"])
    return {"cables": cables, "total": len(cables)}

@api_router.post("/gis/cables")
async def create_gis_cable(
    cable_data: GISCableCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new GIS cable"""
    cable = {
        "id": str(uuid.uuid4()),
        **cable_data.dict(),
        "organization_id": org_id,
        "created_by": current_user["sub"],
        "created_at": datetime.utcnow().isoformat(),
        "updated_at": datetime.utcnow().isoformat(),
        "health_index": 100  # 0-100 health score
    }
    await gis_cables_collection.insert_one(cable)
    return {"id": cable["id"], "message": "Cable created successfully"}

@api_router.put("/gis/cables/{cable_id}")
async def update_gis_cable(
    cable_id: str,
    cable_data: dict,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Update a GIS cable"""
    cable_data["updated_at"] = datetime.utcnow().isoformat()
    result = await gis_cables_collection.update_one(
        {"id": cable_id, "organization_id": org_id},
        {"$set": cable_data}
    )
    if result.modified_count == 0:
        raise HTTPException(status_code=404, detail="Cable not found")
    return {"message": "Cable updated successfully"}

@api_router.delete("/gis/cables/{cable_id}")
async def delete_gis_cable(
    cable_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Delete a GIS cable"""
    result = await gis_cables_collection.delete_one({"id": cable_id, "organization_id": org_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Cable not found")
    return {"message": "Cable deleted successfully"}

# GIS Junctions CRUD
@api_router.get("/gis/junctions")
async def get_gis_junctions(
    junction_type: Optional[str] = None,
    limit: int = 1000,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get all GIS junctions"""
    query = {"organization_id": org_id}
    if junction_type:
        query["junction_type"] = junction_type
    
    junctions = await gis_junctions_collection.find(query).limit(limit).to_list(limit)
    for junction in junctions:
        junction["_id"] = str(junction["_id"])
    return {"junctions": junctions, "total": len(junctions)}

@api_router.post("/gis/junctions")
async def create_gis_junction(
    junction_data: GISJunctionCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new GIS junction"""
    junction = {
        "id": str(uuid.uuid4()),
        **junction_data.dict(),
        "organization_id": org_id,
        "created_by": current_user["sub"],
        "created_at": datetime.utcnow().isoformat(),
        "updated_at": datetime.utcnow().isoformat(),
        "health_index": 100,
        "signal_strength": None  # Will be calculated based on network
    }
    await gis_junctions_collection.insert_one(junction)
    return {"id": junction["id"], "message": "Junction created successfully"}

@api_router.put("/gis/junctions/{junction_id}")
async def update_gis_junction(
    junction_id: str,
    junction_data: dict,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Update a GIS junction"""
    junction_data["updated_at"] = datetime.utcnow().isoformat()
    result = await gis_junctions_collection.update_one(
        {"id": junction_id, "organization_id": org_id},
        {"$set": junction_data}
    )
    if result.modified_count == 0:
        raise HTTPException(status_code=404, detail="Junction not found")
    return {"message": "Junction updated successfully"}

@api_router.delete("/gis/junctions/{junction_id}")
async def delete_gis_junction(
    junction_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Delete a GIS junction"""
    result = await gis_junctions_collection.delete_one({"id": junction_id, "organization_id": org_id})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Junction not found")
    return {"message": "Junction deleted successfully"}

# GIS Incidents CRUD
@api_router.get("/gis/incidents")
async def get_gis_incidents(
    status: Optional[str] = None,
    severity: Optional[str] = None,
    limit: int = 200,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get all GIS incidents"""
    query = {"organization_id": org_id}
    if status:
        query["status"] = status
    if severity:
        query["severity"] = severity
    
    incidents = await gis_incidents_collection.find(query).sort("created_at", -1).limit(limit).to_list(limit)
    for incident in incidents:
        incident["_id"] = str(incident["_id"])
    return {"incidents": incidents, "total": len(incidents)}

@api_router.post("/gis/incidents")
async def create_gis_incident(
    incident_data: GISIncidentCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new GIS incident"""
    incident = {
        "id": str(uuid.uuid4()),
        **incident_data.dict(),
        "organization_id": org_id,
        "reported_by": current_user["sub"],
        "created_at": datetime.utcnow().isoformat(),
        "updated_at": datetime.utcnow().isoformat(),
        "resolved_at": None
    }
    await gis_incidents_collection.insert_one(incident)
    return {"id": incident["id"], "message": "Incident reported successfully"}

@api_router.put("/gis/incidents/{incident_id}")
async def update_gis_incident(
    incident_id: str,
    incident_data: dict,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Update a GIS incident"""
    incident_data["updated_at"] = datetime.utcnow().isoformat()
    if incident_data.get("status") == "resolved":
        incident_data["resolved_at"] = datetime.utcnow().isoformat()
    
    result = await gis_incidents_collection.update_one(
        {"id": incident_id, "organization_id": org_id},
        {"$set": incident_data}
    )
    if result.modified_count == 0:
        raise HTTPException(status_code=404, detail="Incident not found")
    return {"message": "Incident updated successfully"}

# GIS Fibers CRUD
@api_router.get("/gis/fibers")
async def get_gis_fibers(
    cable_id: Optional[str] = None,
    status: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get fibers in a cable"""
    query = {"organization_id": org_id}
    if cable_id:
        query["cable_id"] = cable_id
    if status:
        query["status"] = status
    
    fibers = await gis_fibers_collection.find(query).to_list(500)
    for fiber in fibers:
        fiber["_id"] = str(fiber["_id"])
    return {"fibers": fibers, "total": len(fibers)}

@api_router.post("/gis/fibers")
async def create_gis_fiber(
    fiber_data: GISFiberCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new fiber entry"""
    fiber = {
        "id": str(uuid.uuid4()),
        **fiber_data.dict(),
        "organization_id": org_id,
        "created_at": datetime.utcnow().isoformat()
    }
    await gis_fibers_collection.insert_one(fiber)
    return {"id": fiber["id"], "message": "Fiber created successfully"}

# GIS Signal Strength Calculator
@api_router.post("/gis/calculate-signal")
async def calculate_signal_strength(
    data: dict,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Calculate expected signal strength at junctions given input power"""
    input_power = data.get("input_power_dbm", 0)  # Input signal in dBm
    start_junction_id = data.get("start_junction_id")
    
    # Get all cables and junctions to calculate path
    cables = await gis_cables_collection.find({"organization_id": org_id}).to_list(1000)
    junctions = await gis_junctions_collection.find({"organization_id": org_id}).to_list(1000)
    
    # Build signal strength map
    signal_map = {}
    for junction in junctions:
        # Simple calculation: input - (cable_loss + splice_loss)
        total_loss = 0
        for cable in cables:
            if cable.get("end_junction_id") == junction["id"]:
                cable_loss = cable.get("length_km", 1) * cable.get("loss_per_km", 0.35)
                total_loss += cable_loss
        
        splice_loss = junction.get("splice_loss", 0.1)
        total_loss += splice_loss
        
        signal_strength = input_power - total_loss
        signal_map[junction["id"]] = {
            "junction_name": junction["name"],
            "signal_strength_dbm": round(signal_strength, 2),
            "total_loss_db": round(total_loss, 2)
        }
    
    return {"input_power_dbm": input_power, "junction_signals": signal_map}

# GIS OTDR Fault Location
@api_router.post("/gis/otdr-fault")
async def locate_fault_with_otdr(
    data: dict,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Locate fault using OTDR distance measurement"""
    cable_id = data.get("cable_id")
    fault_distance_km = data.get("fault_distance_km", 0)
    
    cable = await gis_cables_collection.find_one({"id": cable_id, "organization_id": org_id})
    if not cable:
        raise HTTPException(status_code=404, detail="Cable not found")
    
    # Calculate fault position along cable path
    path = cable.get("path", [])
    total_length = cable.get("length_km", 0)
    
    if total_length <= 0 or not path:
        return {"error": "Cable has no path or length data"}
    
    # Linear interpolation along path
    ratio = min(fault_distance_km / total_length, 1.0)
    path_index = int(ratio * (len(path) - 1))
    
    if path_index < len(path):
        fault_location = path[path_index]
    else:
        fault_location = path[-1]
    
    return {
        "cable_id": cable_id,
        "cable_name": cable.get("name"),
        "fault_distance_km": fault_distance_km,
        "estimated_location": fault_location,
        "confidence": "high" if len(path) > 5 else "medium"
    }

# GIS Export KMZ
@api_router.get("/gis/export/kmz")
async def export_gis_as_kmz(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Export GIS data as KMZ/KML format"""
    cables = await gis_cables_collection.find({"organization_id": org_id}).to_list(1000)
    junctions = await gis_junctions_collection.find({"organization_id": org_id}).to_list(1000)
    incidents = await gis_incidents_collection.find({"organization_id": org_id}).to_list(500)
    
    # Generate KML content
    kml_content = '''<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Network Map Export</name>
<description>Exported from NMS GIS Module</description>

<!-- Styles -->
<Style id="cableStyle">
  <LineStyle><color>ff0000ff</color><width>3</width></LineStyle>
</Style>
<Style id="junctionStyle">
  <IconStyle><Icon><href>http://maps.google.com/mapfiles/kml/paddle/blu-circle.png</href></Icon></IconStyle>
</Style>
<Style id="incidentStyle">
  <IconStyle><Icon><href>http://maps.google.com/mapfiles/kml/paddle/red-circle.png</href></Icon></IconStyle>
</Style>

<!-- Cables -->
<Folder><name>Cables</name>
'''
    
    for cable in cables:
        path = cable.get("path", [])
        if path:
            coords = " ".join([f"{p.get('lng', 0)},{p.get('lat', 0)},0" for p in path])
            kml_content += f'''
<Placemark>
  <name>{cable.get('name', 'Cable')}</name>
  <description>Type: {cable.get('cable_type')}, Fibers: {cable.get('fiber_count')}</description>
  <styleUrl>#cableStyle</styleUrl>
  <LineString><coordinates>{coords}</coordinates></LineString>
</Placemark>'''
    
    kml_content += '</Folder>\n<!-- Junctions -->\n<Folder><name>Junctions</name>\n'
    
    for junction in junctions:
        kml_content += f'''
<Placemark>
  <name>{junction.get('name', 'Junction')}</name>
  <description>Type: {junction.get('junction_type')}</description>
  <styleUrl>#junctionStyle</styleUrl>
  <Point><coordinates>{junction.get('longitude', 0)},{junction.get('latitude', 0)},0</coordinates></Point>
</Placemark>'''
    
    kml_content += '</Folder>\n<!-- Incidents -->\n<Folder><name>Incidents</name>\n'
    
    for incident in incidents:
        kml_content += f'''
<Placemark>
  <name>{incident.get('title', 'Incident')}</name>
  <description>Type: {incident.get('incident_type')}, Severity: {incident.get('severity')}</description>
  <styleUrl>#incidentStyle</styleUrl>
  <Point><coordinates>{incident.get('longitude', 0)},{incident.get('latitude', 0)},0</coordinates></Point>
</Placemark>'''
    
    kml_content += '</Folder>\n</Document>\n</kml>'
    
    return {"kml_content": kml_content, "filename": f"network_map_{datetime.utcnow().strftime('%Y%m%d')}.kml"}

# GIS Stats
@api_router.get("/gis/stats")
async def get_gis_stats(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get GIS statistics"""
    org_filter = {"organization_id": org_id}
    cables_count = await gis_cables_collection.count_documents(org_filter)
    junctions_count = await gis_junctions_collection.count_documents(org_filter)
    fibers_count = await gis_fibers_collection.count_documents(org_filter)
    incidents_open = await gis_incidents_collection.count_documents({"organization_id": org_id, "status": "open"})
    incidents_total = await gis_incidents_collection.count_documents(org_filter)
    
    # Calculate total cable length
    cables = await gis_cables_collection.find(org_filter, {"length_km": 1}).to_list(1000)
    total_length = sum(c.get("length_km", 0) for c in cables)
    
    return {
        "cables": cables_count,
        "junctions": junctions_count,
        "fibers": fibers_count,
        "total_cable_length_km": round(total_length, 2),
        "incidents": {"open": incidents_open, "total": incidents_total}
    }



# Admin Dashboard
@api_router.get("/panel/dashboard")
async def get_admin_dashboard(current_user: dict = Depends(get_current_user)):
    """Get admin dashboard stats"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin only")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    org_id = user.get('organization_id') if user else None
    
    stats = await admin_manager.get_admin_dashboard_stats(org_id)
    return stats

# Super Admin - All Organizations (only for first admin)
@api_router.get("/panel/super/organizations")
async def get_all_organizations(current_user: dict = Depends(get_current_user)):
    """Get all organizations (super admin only)"""
    if current_user.get('role') != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Super admin only")
    
    # Check if first user (super admin)
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user or not user.get('is_org_owner'):
        raise HTTPException(status_code=403, detail="Super admin only")
    
    orgs = await db.organizations.find().to_list(100)
    return {"organizations": orgs}

# App Updates Check
@api_router.get("/panel/updates/check")
async def check_app_updates(
    current_version: str = "1.0.0",
    current_user: dict = Depends(get_current_user)
):
    """Check for app updates"""
    update = await admin_manager.check_for_updates(current_version)
    return {"update_available": update is not None, "update": update}

@api_router.get("/panel/updates/latest")
async def get_latest_update(current_user: dict = Depends(get_current_user)):
    """Get latest app update info"""
    update = await admin_manager.get_latest_update()
    return {"latest_update": update}

# ============================================
# Phase 22: Multi-Tenant ISP & Billing Routes
# ============================================

class CustomerCreate(BaseModel):
    name: str
    email: str
    phone: Optional[str] = None
    address: Optional[str] = None
    package_id: Optional[str] = None
    status: str = "active"

class InvoiceCreate(BaseModel):
    customer_id: str
    amount: float
    due_date: str
    items: List[dict] = []
    notes: Optional[str] = None

class PaymentCreate(BaseModel):
    invoice_id: str
    amount: float
    method: str = "cash"  # cash, bank, online
    reference: Optional[str] = None

class PackageCreate(BaseModel):
    name: str
    speed: str
    price: float
    description: Optional[str] = None
    features: List[str] = []

# Customers collection
customers_collection = db.customers
invoices_collection = db.invoices
payments_collection = db.payments
packages_collection = db.packages

@api_router.get("/billing/customers")
async def get_customers(
    skip: int = 0,
    limit: int = 100,
    status: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get all customers"""
    query = {"organization_id": org_id}
    if status:
        query["status"] = status
    
    customers = await customers_collection.find(query).skip(skip).limit(limit).to_list(limit)
    total = await customers_collection.count_documents(query)
    
    for c in customers:
        c["id"] = str(c.pop("_id"))
    
    return {"customers": customers, "total": total}

@api_router.post("/billing/customers")
async def create_customer(
    customer: CustomerCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new customer"""
    customer_data = customer.dict()
    customer_data["organization_id"] = org_id
    customer_data["created_at"] = datetime.utcnow().isoformat()
    customer_data["created_by"] = current_user["id"]
    customer_data["balance"] = 0.0
    
    result = await customers_collection.insert_one(customer_data)
    customer_data["id"] = str(result.inserted_id)
    if "_id" in customer_data:
        del customer_data["_id"]
    
    return {"message": "Customer created", "customer": customer_data}

@api_router.get("/billing/customers/{customer_id}")
async def get_customer(
    customer_id: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get customer details"""
    from bson import ObjectId
    customer = await customers_collection.find_one({"_id": ObjectId(customer_id), "organization_id": org_id})
    if not customer:
        raise HTTPException(status_code=404, detail="Customer not found")
    
    customer["id"] = str(customer.pop("_id"))
    
    # Get customer invoices
    invoices = await invoices_collection.find({"customer_id": customer_id}).to_list(100)
    for inv in invoices:
        inv["id"] = str(inv.pop("_id"))
    
    customer["invoices"] = invoices
    return customer

@api_router.get("/billing/invoices")
async def get_invoices(
    skip: int = 0,
    limit: int = 100,
    status: Optional[str] = None,
    customer_id: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get all invoices"""
    query = {"organization_id": org_id}
    if status:
        query["status"] = status
    if customer_id:
        query["customer_id"] = customer_id
    
    invoices = await invoices_collection.find(query).skip(skip).limit(limit).to_list(limit)
    total = await invoices_collection.count_documents(query)
    
    for inv in invoices:
        inv["id"] = str(inv.pop("_id"))
    
    return {"invoices": invoices, "total": total}

@api_router.post("/billing/invoices")
async def create_invoice(
    invoice: InvoiceCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new invoice"""
    invoice_data = invoice.dict()
    invoice_data["organization_id"] = org_id
    invoice_data["created_at"] = datetime.utcnow().isoformat()
    invoice_data["status"] = "pending"
    invoice_data["invoice_number"] = f"INV-{uuid.uuid4().hex[:8].upper()}"
    invoice_data["paid_amount"] = 0.0
    
    result = await invoices_collection.insert_one(invoice_data)
    invoice_data["id"] = str(result.inserted_id)
    
    return {"message": "Invoice created", "invoice": invoice_data}

@api_router.post("/billing/payments")
async def record_payment(
    payment: PaymentCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Record a payment"""
    from bson import ObjectId
    
    # Get invoice
    invoice = await invoices_collection.find_one({"_id": ObjectId(payment.invoice_id), "organization_id": org_id})
    if not invoice:
        raise HTTPException(status_code=404, detail="Invoice not found")
    
    payment_data = payment.dict()
    payment_data["created_at"] = datetime.utcnow().isoformat()
    payment_data["receipt_number"] = f"RCP-{uuid.uuid4().hex[:8].upper()}"
    payment_data["recorded_by"] = current_user["id"]
    
    result = await payments_collection.insert_one(payment_data)
    payment_data["id"] = str(result.inserted_id)
    
    # Update invoice
    new_paid = invoice.get("paid_amount", 0) + payment.amount
    new_status = "paid" if new_paid >= invoice["amount"] else "partial"
    
    await invoices_collection.update_one(
        {"_id": ObjectId(payment.invoice_id)},
        {"$set": {"paid_amount": new_paid, "status": new_status}}
    )
    
    # Update customer balance
    await customers_collection.update_one(
        {"_id": ObjectId(invoice["customer_id"])},
        {"$inc": {"balance": -payment.amount}}
    )
    
    return {"message": "Payment recorded", "payment": payment_data}

@api_router.get("/billing/packages")
async def get_packages(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get all packages"""
    packages = await packages_collection.find({"organization_id": org_id}).to_list(100)
    for pkg in packages:
        pkg["id"] = str(pkg.pop("_id"))
    return {"packages": packages}

@api_router.post("/billing/packages")
async def create_package(
    package: PackageCreate,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a new package"""
    if current_user.get("role") != UserRole.ADMIN.value:
        raise HTTPException(status_code=403, detail="Admin access required")
    
    package_data = package.dict()
    package_data["organization_id"] = org_id
    package_data["created_at"] = datetime.utcnow().isoformat()
    
    result = await packages_collection.insert_one(package_data)
    package_data["id"] = str(result.inserted_id)
    
    return {"message": "Package created", "package": package_data}

@api_router.get("/billing/stats")
async def get_billing_stats(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get billing statistics"""
    org_filter = {"organization_id": org_id}
    total_customers = await customers_collection.count_documents(org_filter)
    active_customers = await customers_collection.count_documents({"organization_id": org_id, "status": "active"})
    
    pending_invoices = await invoices_collection.count_documents({"organization_id": org_id, "status": "pending"})
    paid_invoices = await invoices_collection.count_documents({"organization_id": org_id, "status": "paid"})
    
    # Calculate revenue this month
    month_start = datetime.utcnow().replace(day=1, hour=0, minute=0, second=0).isoformat()
    monthly_payments = await payments_collection.find(
        {"organization_id": org_id, "created_at": {"$gte": month_start}}
    ).to_list(1000)
    
    monthly_revenue = sum(p.get("amount", 0) for p in monthly_payments)
    
    return {
        "customers": {"total": total_customers, "active": active_customers},
        "invoices": {"pending": pending_invoices, "paid": paid_invoices},
        "revenue": {"monthly": monthly_revenue}
    }


# GIS Feature Tiers API
@api_router.get("/billing/subscription")
async def get_user_subscription_tier(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get current user's subscription tier for feature access"""
    user = await users_collection.find_one({'id': current_user['sub']})
    
    # Check if user has organization with subscription
    if user and user.get('organization_id'):
        # Check for active subscription
        sub = await db.subscriptions.find_one({
            'organization_id': user['organization_id'],
            'status': 'active'
        })
        if sub:
            plan_to_tier = {
                'starter': 'basic',
                'professional': 'premium', 
                'enterprise': 'enterprise'
            }
            return {
                "tier": plan_to_tier.get(sub.get('plan_type'), 'free'),
                "plan": sub.get('plan_type'),
                "expires_at": sub.get('expires_at')
            }
    
    # Default to free tier
    return {"tier": "free", "plan": None, "expires_at": None}

@api_router.post("/billing/upgrade-tier")
async def upgrade_subscription_tier(
    tier: str,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Upgrade user's subscription tier (demo - in production connect to payment)"""
    valid_tiers = ['free', 'basic', 'premium', 'enterprise']
    if tier not in valid_tiers:
        raise HTTPException(status_code=400, detail=f"Invalid tier. Must be one of: {valid_tiers}")
    
    user = await users_collection.find_one({'id': current_user['sub']})
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    # For demo purposes, directly update user's tier
    await users_collection.update_one(
        {'id': current_user['sub']},
        {'$set': {'subscription_tier': tier, 'tier_updated_at': datetime.utcnow().isoformat()}}
    )
    
    return {"message": f"Upgraded to {tier} tier", "tier": tier}



# ============================================
# Phase 25: AI Chat Assistant Routes
# ============================================

class ChatMessage(BaseModel):
    message: str
    context: Optional[dict] = None

class KnowledgeArticle(BaseModel):
    title: str
    content: str
    category: str
    tags: List[str] = []

# Collections for chat
chat_history_collection = db.chat_history
knowledge_base_collection = db.knowledge_base

@api_router.post("/ai/chat")
async def ai_chat(
    chat: ChatMessage,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """AI Chat Assistant endpoint"""
    try:
        # Get user's chat history for context
        history = await chat_history_collection.find(
            {"user_id": current_user["id"], "organization_id": org_id}
        ).sort("created_at", -1).limit(5).to_list(5)
        
        # Build context from history
        context_messages = []
        for h in reversed(history):
            context_messages.append(f"User: {h.get('user_message', '')}")
            context_messages.append(f"Assistant: {h.get('assistant_response', '')}")
        
        # Search knowledge base for relevant info
        search_terms = chat.message.lower().split()
        relevant_articles = await knowledge_base_collection.find({
            "organization_id": org_id,
            "$or": [
                {"title": {"$regex": "|".join(search_terms), "$options": "i"}},
                {"tags": {"$in": search_terms}},
                {"content": {"$regex": "|".join(search_terms[:3]), "$options": "i"}}
            ]
        }).limit(3).to_list(3)
        
        kb_context = ""
        if relevant_articles:
            kb_context = "\n\nRelevant Knowledge Base Info:\n"
            for art in relevant_articles:
                kb_context += f"- {art['title']}: {art['content'][:200]}...\n"
        
        # Use AI Troubleshooter for intelligent response
        system_prompt = f"""You are an AI assistant for a Network Management System. 
You help users with:
- Network troubleshooting and diagnostics
- Device configuration guidance
- ISP and billing queries
- System usage help

Previous conversation:
{chr(10).join(context_messages[-6:])}
{kb_context}

Be helpful, concise, and technical when needed. If you don't know something, say so.
"""
        
        # Generate response using AI
        response = await ai_troubleshooter.generate_ai_response(
            system_prompt,
            chat.message
        )
        
        # Save to chat history
        chat_record = {
            "user_id": current_user["id"],
            "organization_id": org_id,
            "user_message": chat.message,
            "assistant_response": response,
            "context": chat.context,
            "created_at": datetime.utcnow().isoformat()
        }
        await chat_history_collection.insert_one(chat_record)
        
        return {
            "response": response,
            "sources": [{"title": a["title"], "category": a.get("category", "general")} for a in relevant_articles]
        }
        
    except Exception as e:
        logger.error(f"AI Chat error: {e}")
        # Fallback response
        return {
            "response": "I apologize, but I'm having trouble processing your request right now. Please try again or contact support if the issue persists.",
            "sources": [],
            "error": True
        }

@api_router.get("/ai/chat/history")
async def get_chat_history(
    limit: int = 50,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get user's chat history"""
    history = await chat_history_collection.find(
        {"user_id": current_user["id"], "organization_id": org_id}
    ).sort("created_at", -1).limit(limit).to_list(limit)
    
    for h in history:
        h["id"] = str(h.pop("_id"))
    
    return {"history": list(reversed(history))}

@api_router.delete("/ai/chat/history")
async def clear_chat_history(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Clear user's chat history"""
    result = await chat_history_collection.delete_many({"user_id": current_user["id"], "organization_id": org_id})
    return {"message": f"Cleared {result.deleted_count} messages"}

@api_router.get("/ai/knowledge")
async def get_knowledge_articles(
    category: Optional[str] = None,
    search: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get knowledge base articles"""
    query = {"organization_id": org_id}
    if category:
        query["category"] = category
    if search:
        query["$or"] = [
            {"title": {"$regex": search, "$options": "i"}},
            {"content": {"$regex": search, "$options": "i"}},
            {"tags": {"$in": [search.lower()]}}
        ]
    
    articles = await knowledge_base_collection.find(query).limit(50).to_list(50)
    for art in articles:
        art["id"] = str(art.pop("_id"))
    
    return {"articles": articles}

@api_router.post("/ai/knowledge")
async def create_knowledge_article(
    article: KnowledgeArticle,
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Create a knowledge base article"""
    if current_user.get("role") not in [UserRole.ADMIN.value, UserRole.ENGINEER.value]:
        raise HTTPException(status_code=403, detail="Admin or Engineer access required")
    
    article_data = article.dict()
    article_data["organization_id"] = org_id
    article_data["created_at"] = datetime.utcnow().isoformat()
    article_data["created_by"] = current_user["id"]
    
    result = await knowledge_base_collection.insert_one(article_data)
    article_data["id"] = str(result.inserted_id)
    
    return {"message": "Article created", "article": article_data}

@api_router.get("/ai/knowledge/categories")
async def get_knowledge_categories(
    current_user: dict = Depends(get_current_user),
    org_id: str = Depends(get_current_org)
):
    """Get knowledge base categories"""
    categories = await knowledge_base_collection.distinct("category", {"organization_id": org_id})
    return {"categories": categories}

# ============================================
# Help & Documentation
# ============================================

help_docs_collection = db.help_docs

class HelpDocCreate(BaseModel):
    title: str
    content: str
    category: str = "general"
    icon: str = "document-text-outline"
    order: int = 0
    is_published: bool = True

class HelpDocUpdate(BaseModel):
    title: Optional[str] = None
    content: Optional[str] = None
    category: Optional[str] = None
    icon: Optional[str] = None
    order: Optional[int] = None
    is_published: Optional[bool] = None

@api_router.get("/help-docs")
async def get_help_docs(
    category: Optional[str] = None,
    search: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
):
    """Get all published help documents (all authenticated users)"""
    query: dict = {"is_published": True}
    is_super = current_user.get("role") == UserRole.SUPER_ADMIN.value
    if is_super:
        query.pop("is_published", None)
    if category:
        query["category"] = category
    if search:
        query["$or"] = [
            {"title": {"$regex": search, "$options": "i"}},
            {"content": {"$regex": search, "$options": "i"}},
        ]

    docs = await help_docs_collection.find(query).sort("order", 1).to_list(200)
    for doc in docs:
        doc["id"] = str(doc.pop("_id"))
    return {"docs": docs}

@api_router.get("/help-docs/categories")
async def get_help_doc_categories(
    current_user: dict = Depends(get_current_user),
):
    """Get distinct help document categories"""
    categories = await help_docs_collection.distinct("category", {"is_published": True})
    return {"categories": categories}

@api_router.get("/help-docs/{doc_id}")
async def get_help_doc(
    doc_id: str,
    current_user: dict = Depends(get_current_user),
):
    """Get a single help document"""
    from bson import ObjectId
    doc = await help_docs_collection.find_one({"_id": ObjectId(doc_id)})
    if not doc:
        raise HTTPException(status_code=404, detail="Document not found")
    doc["id"] = str(doc.pop("_id"))
    return doc

@api_router.post("/help-docs")
async def create_help_doc(
    doc: HelpDocCreate,
    current_user: dict = Depends(get_current_user),
):
    """Create a help document (super admin only)"""
    if current_user.get("role") != UserRole.SUPER_ADMIN.value:
        raise HTTPException(status_code=403, detail="Super admin access required")

    doc_data = doc.dict()
    doc_data["created_at"] = datetime.utcnow().isoformat()
    doc_data["updated_at"] = datetime.utcnow().isoformat()
    doc_data["created_by"] = current_user.get("sub", current_user.get("id", ""))

    result = await help_docs_collection.insert_one(doc_data)
    doc_data["id"] = str(result.inserted_id)
    del doc_data["_id"]
    return {"message": "Document created", "doc": doc_data}

@api_router.put("/help-docs/{doc_id}")
async def update_help_doc(
    doc_id: str,
    doc: HelpDocUpdate,
    current_user: dict = Depends(get_current_user),
):
    """Update a help document (super admin only)"""
    if current_user.get("role") != UserRole.SUPER_ADMIN.value:
        raise HTTPException(status_code=403, detail="Super admin access required")

    from bson import ObjectId
    update_data = {k: v for k, v in doc.dict().items() if v is not None}
    update_data["updated_at"] = datetime.utcnow().isoformat()

    result = await help_docs_collection.update_one(
        {"_id": ObjectId(doc_id)}, {"$set": update_data}
    )
    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Document not found")

    updated = await help_docs_collection.find_one({"_id": ObjectId(doc_id)})
    updated["id"] = str(updated.pop("_id"))
    return {"message": "Document updated", "doc": updated}

@api_router.delete("/help-docs/{doc_id}")
async def delete_help_doc(
    doc_id: str,
    current_user: dict = Depends(get_current_user),
):
    """Delete a help document (super admin only)"""
    if current_user.get("role") != UserRole.SUPER_ADMIN.value:
        raise HTTPException(status_code=403, detail="Super admin access required")

    from bson import ObjectId
    result = await help_docs_collection.delete_one({"_id": ObjectId(doc_id)})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Document not found")
    return {"message": "Document deleted"}

@api_router.post("/help-docs/seed")
async def seed_help_docs(
    current_user: dict = Depends(get_current_user),
):
    """Seed default help documents (super admin only)"""
    if current_user.get("role") != UserRole.SUPER_ADMIN.value:
        raise HTTPException(status_code=403, detail="Super admin access required")

    existing = await help_docs_collection.count_documents({})
    if existing > 0:
        return {"message": f"Help docs already exist ({existing} docs). Skipping seed.", "seeded": 0}

    default_docs = [
        {
            "title": "Getting Started with NMS eSafe",
            "content": """Welcome to the Network Management System (NMS) eSafe! This guide will help you get started.\n\n**Step 1: Dashboard Overview**\nAfter logging in, you'll see your Dashboard with key metrics — total devices, online/offline status, recent alerts, and scan history.\n\n**Step 2: Adding Devices**\nGo to the Scanner tab and enter a subnet (e.g., 192.168.1.0/24) to auto-discover devices. Discovered devices will appear in the Devices tab.\n\n**Step 3: Monitoring**\nOnce devices are added, the system automatically monitors their status. You'll receive alerts when devices go offline.\n\n**Step 4: Navigation**\nUse the bottom tab bar to navigate between Home, Devices, Scanner, Admin (if you're an admin), and Profile.""",
            "category": "Getting Started",
            "icon": "rocket-outline",
            "order": 1,
            "is_published": True,
        },
        {
            "title": "Scanning Your Network",
            "content": """Learn how to discover devices on your network.\n\n**Quick Scan**\nNavigate to the Scanner tab and enter a subnet range (e.g., 192.168.1.0/24). Tap \"Start Scan\" to begin discovery.\n\n**Scan Options**\n- **Port Scanning**: Enable to detect open ports on each device\n- **SNMP Check**: Enable to query SNMP-capable devices for system info\n- **SNMP Community**: Set the community string (default: \"public\")\n\n**Scan Results**\nAfter the scan completes, new devices are automatically added to your inventory with:\n- IP Address & MAC Address\n- Hostname (if available)\n- Vendor identification\n- Open ports list\n- SNMP system description\n\n**Scan History**\nView previous scan results from the Scanner tab's history section.""",
            "category": "Network Discovery",
            "icon": "scan-outline",
            "order": 2,
            "is_published": True,
        },
        {
            "title": "Managing Devices",
            "content": """How to view, edit, and manage your discovered network devices.\n\n**Device List**\nThe Devices tab shows all discovered devices with status indicators (green = online, red = offline).\n\n**Device Details**\nTap any device to view details including:\n- IP address, MAC address, and hostname\n- Vendor and device type\n- Open ports\n- SNMP information\n- Last seen timestamp\n\n**Edit Device**\nAdmins and engineers can update device info:\n- Hostname and location\n- Notes for documentation\n- SNMP community string\n\n**Delete Device**\nSwipe left or tap the delete button to remove a device from monitoring.\n\n**Device Monitoring**\nTap \"Monitor\" to see real-time device metrics and performance data.""",
            "category": "Device Management",
            "icon": "hardware-chip-outline",
            "order": 3,
            "is_published": True,
        },
        {
            "title": "MikroTik Device Management",
            "content": """Manage your MikroTik routers and switches directly from the app.\n\n**Connecting to MikroTik**\nFrom a device's details, tap \"MikroTik\" and enter your device credentials (username/password).\n\n**Available Features**\n- **System Resources**: View CPU, memory, uptime, and board info\n- **Interfaces**: See all network interfaces with traffic stats\n- **DHCP Leases**: View active DHCP leases\n- **PPPoE**: Monitor PPPoE client connections\n- **Queues**: View bandwidth queues and limits\n- **Firewall**: Inspect firewall filter rules\n- **Backup**: Create and download device backups\n\n**Requirements**\n- Device must be reachable via API (port 8728)\n- Valid admin credentials required\n- API service must be enabled on the MikroTik device""",
            "category": "Vendor Specific",
            "icon": "server-outline",
            "order": 4,
            "is_published": True,
        },
        {
            "title": "Cisco Device Management",
            "content": """Manage Cisco IOS, IOS-XE, and NX-OS devices.\n\n**Connecting to Cisco Devices**\nFrom device details, tap \"Cisco\" and provide SSH credentials.\n\n**Available Features**\n- **Version Info**: View IOS version, hardware model, and serial number\n- **Interfaces**: See interface status, IP addresses, and traffic counters\n- **Backup**: Create full running-config backups\n\n**Supported Device Types**\n- Cisco IOS (routers, switches)\n- Cisco IOS-XE\n- Cisco NX-OS (Nexus)\n\n**Requirements**\n- SSH access must be enabled\n- Valid credentials with privilege level 15 recommended""",
            "category": "Vendor Specific",
            "icon": "git-network-outline",
            "order": 5,
            "is_published": True,
        },
        {
            "title": "Huawei OLT Management",
            "content": """Manage Huawei OLT devices and ONUs.\n\n**Connecting**\nFrom device details, tap \"Huawei OLT\" and provide telnet/SSH credentials.\n\n**Available Features**\n- **ONU List**: View all registered ONUs with status\n- **Optical Power**: Check ONU optical signal levels (Rx/Tx power)\n- **ONU Reboot**: Remotely reboot individual ONUs\n\n**Frame/Slot/Port**\nSpecify the frame, slot, and port to query specific GPON interfaces. Defaults: Frame 0, Slot 0, Port 0.\n\n**Signal Quality**\nOptical power readings help diagnose fiber issues:\n- Normal: -8 to -25 dBm\n- Warning: -25 to -28 dBm\n- Critical: Below -28 dBm""",
            "category": "Vendor Specific",
            "icon": "flash-outline",
            "order": 6,
            "is_published": True,
        },
        {
            "title": "AI Configuration Engine",
            "content": """Use AI-powered tools to generate, validate, and optimize device configurations.\n\n**Generate Configurations**\nDescribe what you need in plain language, and the AI will generate vendor-specific configs.\nExample: \"Configure VLAN 100 for the sales department with DHCP on Cisco IOS\"\n\n**Config Features**\n- **Generate**: Create new configurations from requirements\n- **Validate**: Check existing configs for errors and best practices\n- **Optimize**: Get suggestions to improve performance and security\n- **Explain**: Get plain-language explanations of complex configs\n\n**Supported Vendors**\n- Cisco IOS/IOS-XE/NX-OS\n- MikroTik RouterOS\n- Huawei VRP\n- Generic networking configs\n\n**AI Chat**\nUse the AI Chat feature for interactive troubleshooting and configuration assistance.""",
            "category": "AI Features",
            "icon": "sparkles-outline",
            "order": 7,
            "is_published": True,
        },
        {
            "title": "Network Troubleshooting",
            "content": """Diagnose and resolve network issues using built-in tools.\n\n**Device Health Check**\nView real-time health metrics for any device including:\n- Response time and packet loss\n- Interface utilization\n- Error counters\n\n**AI Diagnostics**\nDescribe a network issue in plain language and get AI-powered diagnosis with step-by-step resolution guides.\n\n**Log Analysis**\nPaste device logs for automated analysis. The AI identifies patterns, errors, and provides actionable recommendations.\n\n**Network Health Dashboard**\nThe Network Health screen provides an overview of your entire network's status with:\n- Overall health score\n- Device availability percentage\n- Active alerts summary\n- Top issues requiring attention\n\n**Predictive Analysis**\nThe system can predict potential issues before they occur based on historical trends.""",
            "category": "Troubleshooting",
            "icon": "medkit-outline",
            "order": 8,
            "is_published": True,
        },
        {
            "title": "GIS Network Map",
            "content": """Visualize your network infrastructure on an interactive map.\n\n**Map Features**\n- **Device Markers**: See all network devices plotted on the map\n- **Fiber Cables**: Draw and track fiber optic cable routes\n- **Junctions**: Mark splice points, manholes, and distribution points\n- **Incidents**: Report and track fiber cuts and outages\n\n**Cable Management**\n- Draw cable paths on the map\n- Track fiber count, type, and specifications\n- Calculate signal loss over distance\n\n**OTDR Fault Location**\nEnter the fault distance from an OTDR reading to pinpoint the exact location of a fiber break on the map.\n\n**Export**\nExport your network map data in KMZ format for use in Google Earth or other GIS applications.""",
            "category": "Advanced Features",
            "icon": "map-outline",
            "order": 9,
            "is_published": True,
        },
        {
            "title": "Billing & Customer Management",
            "content": """Manage ISP customers, packages, invoices, and payments.\n\n**Customers**\n- Add and manage customer profiles\n- Assign internet packages\n- Track customer status (active, suspended, etc.)\n\n**Packages**\nCreate internet service packages with:\n- Speed tier (e.g., 50 Mbps, 100 Mbps)\n- Monthly price\n- Features list\n\n**Invoices**\n- Generate monthly invoices\n- Track payment status\n- Set due dates\n\n**Payments**\n- Record payments against invoices\n- Support multiple payment methods\n- Track payment references\n\n**Billing Dashboard**\nView billing statistics including total revenue, outstanding amounts, and collection rates.""",
            "category": "Billing",
            "icon": "card-outline",
            "order": 10,
            "is_published": True,
        },
        {
            "title": "Alerts & Notifications",
            "content": """Stay informed about network events and issues.\n\n**Alert Types**\n- **Critical**: Device down, link failure\n- **Warning**: High CPU, memory threshold exceeded\n- **Info**: Device discovered, scan completed\n\n**Managing Alerts**\n- View all alerts from the Alerts screen\n- Filter by severity and status\n- Acknowledge alerts to mark them as reviewed\n- Delete resolved alerts\n\n**Automatic Monitoring**\nThe system continuously monitors all devices and generates alerts when:\n- A device goes offline\n- Response time exceeds thresholds\n- SNMP metrics indicate problems\n- Interface errors are detected""",
            "category": "Monitoring",
            "icon": "notifications-outline",
            "order": 11,
            "is_published": True,
        },
        {
            "title": "User Roles & Permissions",
            "content": """Understanding user roles in NMS eSafe.\n\n**Super Admin**\n- Full system access across all organizations\n- Manage all users, organizations, and settings\n- Access super admin panel\n- Manage help documentation\n\n**Admin**\n- Full access within their organization\n- Manage users and approve registrations\n- Configure organization settings\n- Access admin panel features\n\n**Engineer**\n- Device management and configuration\n- Run network scans\n- Use AI tools and troubleshooting\n- Create and view reports\n\n**Viewer**\n- Read-only access to dashboards and devices\n- View alerts and reports\n- Cannot modify devices or settings\n\n**Changing Roles**\nOnly admins and super admins can change user roles. Contact your organization admin if you need elevated access.""",
            "category": "User Guide",
            "icon": "people-outline",
            "order": 12,
            "is_published": True,
        },
        {
            "title": "Admin Panel Guide",
            "content": """Features available in the Admin Panel for organization administrators.\n\n**Dashboard**\nView organization-wide statistics — users, devices, tickets, and recent activity.\n\n**User Management**\n- View and manage all users in your organization\n- Approve or reject pending registrations\n- Suspend or deactivate user accounts\n\n**Feature Toggles**\nEnable or disable specific features for your organization.\n\n**Branding**\nCustomize your organization's appearance:\n- Logo and front image\n- Primary color theme\n- Organization name\n\n**API Settings**\nManage third-party API keys (e.g., OpenAI for AI features).\n\n**Support Tickets**\nCreate and manage support tickets for issues you can't resolve.\n\n**Billing & Subscription**\nManage your organization's subscription plan and view invoices.""",
            "category": "Administration",
            "icon": "settings-outline",
            "order": 13,
            "is_published": True,
        },
        {
            "title": "Reports & Analytics",
            "content": """Generate and view network reports.\n\n**Available Reports**\n- **Daily Report**: Summary of the day's network activity\n- **Weekly Report**: Week-over-week trends and comparisons\n- **Device Report**: Detailed history for a specific device\n- **Vendor Report**: Breakdown of devices by vendor\n\n**Traffic Analysis**\n- **Top Talkers**: Identify devices generating the most traffic\n- **Applications**: See traffic broken down by application\n- **Protocols**: Protocol distribution across the network\n- **Timeline**: Traffic trends over time\n- **Conversations**: Top traffic flows between device pairs\n\n**Using Reports**\nReports help identify:\n- Network bottlenecks\n- Unusual traffic patterns\n- Capacity planning needs\n- Security anomalies""",
            "category": "Advanced Features",
            "icon": "bar-chart-outline",
            "order": 14,
            "is_published": True,
        },
        {
            "title": "Frequently Asked Questions",
            "content": """**Q: How do I add a new device?**\nA: Go to the Scanner tab, enter the device's subnet, and run a scan. The device will be automatically discovered and added.\n\n**Q: Why can't I see the Admin tab?**\nA: The Admin tab is only visible to users with Admin or Super Admin roles. Contact your administrator for access.\n\n**Q: How do I change my password?**\nA: Currently, password changes must be done through your administrator. Contact them for assistance.\n\n**Q: My device shows as offline but it's running. What do I do?**\nA: Check that the device is reachable from the NMS server. Verify firewall rules allow ICMP and SNMP traffic. Try running a new scan.\n\n**Q: How often does the system check device status?**\nA: The monitoring system checks all devices every 5 minutes by default.\n\n**Q: Can I export data from the app?**\nA: Yes, GIS map data can be exported in KMZ format. Reports can be viewed on-screen with key metrics.\n\n**Q: How do I get AI features working?**\nA: An admin needs to add an OpenAI API key in Admin Panel > API Settings. Once configured, AI features are available to all users.\n\n**Q: What browsers/devices are supported?**\nA: NMS eSafe is a mobile application built with React Native, supporting both iOS and Android devices.""",
            "category": "FAQ",
            "icon": "help-circle-outline",
            "order": 15,
            "is_published": True,
        },
    ]

    now = datetime.utcnow().isoformat()
    for d in default_docs:
        d["created_at"] = now
        d["updated_at"] = now
        d["created_by"] = current_user.get("sub", "system")

    await help_docs_collection.insert_many(default_docs)
    return {"message": f"Seeded {len(default_docs)} help documents", "seeded": len(default_docs)}

# ============================================
# Health Check
# ============================================

@api_router.get("/")
async def root():
    return {"message": "Network Management System API", "version": "1.0.0"}

@api_router.get("/health")
async def health_check():
    return {"status": "healthy"}

# Include the router in the main app
app.include_router(api_router)
init_auth_db(db)
init_super_admin(db)
app.include_router(super_admin_router)
init_admin_user_management(db)
app.include_router(admin_user_mgmt_router)
init_support_ticket_system(db)
app.include_router(support_ticket_router)

app.add_middleware(
    CORSMiddleware,
    allow_credentials=True,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.on_event("startup")
async def startup_event():
    """Start background monitoring and ensure indexes"""
    global monitoring_task
    logger.info("Creating organization_id indexes...")
    await devices_collection.create_index("organization_id")
    await devices_collection.create_index("scanned_by")
    await devices_collection.create_index("created_by")
    await devices_collection.create_index([("ip", 1), ("organization_id", 1)])
    await scans_collection.create_index("organization_id")
    await scans_collection.create_index("created_by")
    await alerts_collection.create_index("organization_id")
    await metrics_collection.create_index("organization_id")
    await db.organizations.create_index("id", unique=True)
    await db.backups.create_index("organization_id")
    await db.assets.create_index("organization_id")
    await db.netflow_records.create_index("organization_id")
    await db.gis_cables.create_index("organization_id")
    await db.gis_junctions.create_index("organization_id")
    await db.gis_fibers.create_index("organization_id")
    await db.gis_incidents.create_index("organization_id")
    await db.customers.create_index("organization_id")
    await db.invoices.create_index("organization_id")
    await db.payments.create_index("organization_id")
    await db.packages.create_index("organization_id")
    await db.chat_history.create_index("organization_id")
    await db.knowledge_base.create_index("organization_id")
    await users_collection.create_index("organization_id")
    await db.help_docs.create_index("category")
    await db.help_docs.create_index("order")
    await db.internal_tickets.create_index("organization_id")
    await db.internal_tickets.create_index("user_id")
    await db.platform_tickets.create_index("organization_id")
    await db.platform_tickets.create_index("status")
    logger.info("Indexes created.")
    
    logger.info("Starting device monitoring...")
    monitoring_task = asyncio.create_task(monitor.start_monitoring())

@app.on_event("shutdown")
async def shutdown_db_client():
    """Cleanup on shutdown"""
    logger.info("Shutting down...")
    if monitoring_task:
        monitor.stop_monitoring()
        monitoring_task.cancel()
    client.close()
