from typing import Dict, List, Optional
from datetime import datetime, timedelta
import uuid
import logging

logger = logging.getLogger(__name__)

class AssetManager:
    """Network asset and inventory management"""
    
    def __init__(self, db):
        self.db = db
    
    async def create_asset(self, device_id: str, asset_data: Dict, org_id: str = None) -> Dict:
        """Create asset record for device"""
        query = {'id': device_id}
        if org_id:
            query['organization_id'] = org_id
        device = await self.db.devices.find_one(query)
        if not device:
            raise Exception("Device not found")
        
        asset = {
            'id': str(uuid.uuid4()),
            'device_id': device_id,
            'asset_tag': asset_data.get('asset_tag', f"ASSET-{str(uuid.uuid4())[:8].upper()}"),
            'serial_number': asset_data.get('serial_number'),
            'model_number': asset_data.get('model_number'),
            'manufacturer': asset_data.get('manufacturer', device.get('vendor')),
            'purchase_date': asset_data.get('purchase_date'),
            'purchase_price': asset_data.get('purchase_price'),
            'warranty_expires': asset_data.get('warranty_expires'),
            'location': asset_data.get('location'),
            'department': asset_data.get('department'),
            'owner': asset_data.get('owner'),
            'notes': asset_data.get('notes'),
            'status': 'active',
            'created_at': datetime.utcnow(),
            'updated_at': datetime.utcnow()
        }
        if org_id:
            asset['organization_id'] = org_id
        
        await self.db.assets.insert_one(asset)
        
        # Update device with asset reference
        await self.db.devices.update_one(
            {'id': device_id},
            {'$set': {'asset_id': asset['id']}}
        )
        
        logger.info(f"Created asset record for device {device_id}")
        return asset
    
    async def get_asset(self, asset_id: str, org_id: str = None) -> Optional[Dict]:
        """Get asset by ID"""
        query = {'id': asset_id}
        if org_id:
            query['organization_id'] = org_id
        asset = await self.db.assets.find_one(query)
        return asset
    
    async def get_device_asset(self, device_id: str, org_id: str = None) -> Optional[Dict]:
        """Get asset for device"""
        query = {'device_id': device_id}
        if org_id:
            query['organization_id'] = org_id
        asset = await self.db.assets.find_one(query)
        return asset
    
    async def update_asset(self, asset_id: str, update_data: Dict, org_id: str = None) -> Dict:
        """Update asset information"""
        update_data['updated_at'] = datetime.utcnow()
        
        query = {'id': asset_id}
        if org_id:
            query['organization_id'] = org_id
        
        await self.db.assets.update_one(
            query,
            {'$set': update_data}
        )
        
        return await self.get_asset(asset_id, org_id=org_id)
    
    async def get_warranty_expiring(self, days: int = 90, org_id: str = None) -> List[Dict]:
        """Get assets with warranty expiring soon"""
        future_date = datetime.utcnow() + timedelta(days=days)
        
        query = {
            'warranty_expires': {
                '$gte': datetime.utcnow(),
                '$lte': future_date
            },
            'status': 'active'
        }
        if org_id:
            query['organization_id'] = org_id
        
        assets = await self.db.assets.find(query).sort('warranty_expires', 1).to_list(100)
        
        # Enrich with device info
        enriched = []
        for asset in assets:
            device = await self.db.devices.find_one({'id': asset['device_id']})
            if device:
                asset['device_ip'] = device['ip']
                asset['device_hostname'] = device.get('hostname', device['ip'])
                days_remaining = (asset['warranty_expires'] - datetime.utcnow()).days
                asset['days_remaining'] = days_remaining
                enriched.append(asset)
        
        return enriched
    
    async def get_assets_by_location(self, location: str, org_id: str = None) -> List[Dict]:
        """Get assets by location scoped to organization"""
        query = {'location': location}
        if org_id:
            query['organization_id'] = org_id
        assets = await self.db.assets.find(query).to_list(1000)
        return assets
    
    async def get_assets_by_status(self, status: str, org_id: str = None) -> List[Dict]:
        """Get assets by status scoped to organization"""
        query = {'status': status}
        if org_id:
            query['organization_id'] = org_id
        assets = await self.db.assets.find(query).to_list(1000)
        return assets
    
    async def generate_inventory_report(self, org_id: str = None) -> Dict:
        """Generate complete inventory report"""
        org_filter = {"organization_id": org_id} if org_id else {}
        total_assets = await self.db.assets.count_documents(org_filter)
        
        # By status
        status_counts = {}
        for s in ['active', 'retired', 'maintenance', 'lost']:
            count = await self.db.assets.count_documents({**org_filter, 'status': s})
            status_counts[s] = count
        
        match_stage = [{"$match": org_filter}] if org_filter else []
        
        pipeline = match_stage + [
            {'$group': {'_id': '$manufacturer', 'count': {'$sum': 1}}},
            {'$sort': {'count': -1}}
        ]
        by_manufacturer = await self.db.assets.aggregate(pipeline).to_list(100)
        
        pipeline = match_stage + [
            {'$group': {'_id': '$location', 'count': {'$sum': 1}}},
            {'$sort': {'count': -1}}
        ]
        by_location = await self.db.assets.aggregate(pipeline).to_list(100)
        
        pipeline = match_stage + [
            {'$match': {'purchase_price': {'$exists': True, '$ne': None}}},
            {'$group': {'_id': None, 'total': {'$sum': '$purchase_price'}}}
        ]
        value_result = await self.db.assets.aggregate(pipeline).to_list(1)
        total_value = value_result[0]['total'] if value_result else 0
        
        warranty_active = await self.db.assets.count_documents({
            **org_filter,
            'warranty_expires': {'$gte': datetime.utcnow()},
            'status': 'active'
        })
        warranty_expired = await self.db.assets.count_documents({
            **org_filter,
            'warranty_expires': {'$lt': datetime.utcnow()},
            'status': 'active'
        })
        
        return {
            'generated_at': datetime.utcnow().isoformat(),
            'summary': {
                'total_assets': total_assets,
                'total_value': total_value,
                'by_status': status_counts,
                'warranty_active': warranty_active,
                'warranty_expired': warranty_expired
            },
            'by_manufacturer': [
                {'manufacturer': item['_id'] or 'Unknown', 'count': item['count']}
                for item in by_manufacturer
            ],
            'by_location': [
                {'location': item['_id'] or 'Unassigned', 'count': item['count']}
                for item in by_location
            ]
        }
    
    async def track_asset_movement(self, asset_id: str, from_location: str,
                                  to_location: str, moved_by: str,
                                  notes: Optional[str] = None,
                                  org_id: str = None):
        """Track asset movement between locations scoped to organization"""
        if org_id:
            asset = await self.get_asset(asset_id, org_id=org_id)
            if not asset:
                raise Exception("Asset not found in this organization")
        
        movement = {
            'id': str(uuid.uuid4()),
            'asset_id': asset_id,
            'from_location': from_location,
            'to_location': to_location,
            'moved_at': datetime.utcnow(),
            'moved_by': moved_by,
            'notes': notes
        }
        if org_id:
            movement['organization_id'] = org_id
        
        await self.db.asset_movements.insert_one(movement)
        
        await self.update_asset(asset_id, {'location': to_location}, org_id=org_id)
        
        logger.info(f"Asset {asset_id} moved from {from_location} to {to_location}")
        return movement
    
    async def get_asset_history(self, asset_id: str, org_id: str = None) -> List[Dict]:
        """Get asset movement history scoped to organization"""
        query = {'asset_id': asset_id}
        if org_id:
            query['organization_id'] = org_id
        movements = await self.db.asset_movements.find(query).sort('moved_at', -1).to_list(100)
        
        return movements
