"""
Admin Panel Manager - Comprehensive admin functionality
"""
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
import logging
import uuid
import secrets
import hashlib

logger = logging.getLogger(__name__)


class AdminPanelManager:
    """Manages all admin panel functionality"""
    
    def __init__(self, db):
        self.db = db
    
    # ==================== Organization Management ====================
    
    async def create_organization(self, name: str, owner_id: str, 
                                  domain: Optional[str] = None,
                                  plan: str = "free") -> Dict:
        """Create a new organization/tenant"""
        org = {
            'id': str(uuid.uuid4()),
            'name': name,
            'domain': domain,
            'logo_url': None,
            'front_image_url': None,
            'primary_color': '#3b82f6',
            'plan': plan,
            'owner_id': owner_id,
            'created_at': datetime.utcnow(),
            'is_active': True,
            'settings': {},
            'features_enabled': self._get_default_features(plan),
            'api_key': secrets.token_urlsafe(32),
            'max_users': self._get_plan_limits(plan)['users'],
            'max_devices': self._get_plan_limits(plan)['devices'],
        }
        
        await self.db.organizations.insert_one(org)
        
        # Update user with organization
        await self.db.users.update_one(
            {'id': owner_id},
            {'$set': {'organization_id': org['id'], 'is_org_owner': True}}
        )
        
        return org
    
    async def get_organization(self, org_id: str) -> Optional[Dict]:
        """Get organization by ID"""
        return await self.db.organizations.find_one({'id': org_id})
    
    async def update_organization(self, org_id: str, updates: Dict) -> Dict:
        """Update organization settings"""
        allowed_fields = ['name', 'domain', 'logo_url', 'front_image_url', 
                         'primary_color', 'settings', 'features_enabled']
        
        update_data = {k: v for k, v in updates.items() if k in allowed_fields}
        update_data['updated_at'] = datetime.utcnow()
        
        await self.db.organizations.update_one(
            {'id': org_id},
            {'$set': update_data}
        )
        
        return await self.get_organization(org_id)
    
    async def update_branding(self, org_id: str, logo_url: Optional[str] = None,
                             front_image_url: Optional[str] = None,
                             primary_color: Optional[str] = None,
                             name: Optional[str] = None) -> Dict:
        """Update organization branding"""
        updates = {'updated_at': datetime.utcnow()}
        
        if logo_url is not None:
            updates['logo_url'] = logo_url
        if front_image_url is not None:
            updates['front_image_url'] = front_image_url
        if primary_color is not None:
            updates['primary_color'] = primary_color
        if name is not None:
            updates['name'] = name
        
        await self.db.organizations.update_one(
            {'id': org_id},
            {'$set': updates}
        )
        
        return await self.get_organization(org_id)
    
    async def regenerate_api_key(self, org_id: str) -> str:
        """Regenerate organization API key"""
        new_key = secrets.token_urlsafe(32)
        
        await self.db.organizations.update_one(
            {'id': org_id},
            {'$set': {'api_key': new_key, 'api_key_updated_at': datetime.utcnow()}}
        )
        
        return new_key
    
    def _get_default_features(self, plan: str) -> Dict[str, bool]:
        """Get default features based on plan"""
        base_features = {
            'snmp_enabled': True,
            'mikrotik_enabled': True,
            'cisco_enabled': True,
            'huawei_enabled': True,
            'topology_enabled': True,
            'alerts_enabled': True,
            'reports_enabled': True,
            'backups_enabled': True,
            'map_enabled': True,
            'support_enabled': True,
        }
        
        if plan in ['pro', 'enterprise']:
            base_features.update({
                'ai_config_enabled': True,
                'ai_troubleshoot_enabled': True,
                'traffic_analysis_enabled': True,
                'firmware_enabled': True,
                'assets_enabled': True,
            })
        
        if plan == 'enterprise':
            base_features['billing_enabled'] = True
        
        return base_features
    
    def _get_plan_limits(self, plan: str) -> Dict[str, int]:
        """Get plan limits"""
        limits = {
            'free': {'users': 3, 'devices': 25},
            'basic': {'users': 10, 'devices': 100},
            'pro': {'users': 50, 'devices': 500},
            'enterprise': {'users': 999, 'devices': 9999},
        }
        return limits.get(plan, limits['free'])
    
    # ==================== Feature Toggles ====================
    
    async def update_features(self, org_id: str, features: Dict[str, bool]) -> Dict:
        """Update organization feature toggles"""
        await self.db.organizations.update_one(
            {'id': org_id},
            {'$set': {'features_enabled': features, 'updated_at': datetime.utcnow()}}
        )
        
        return await self.get_organization(org_id)
    
    async def toggle_feature(self, org_id: str, feature: str, enabled: bool) -> Dict:
        """Toggle single feature"""
        await self.db.organizations.update_one(
            {'id': org_id},
            {'$set': {f'features_enabled.{feature}': enabled, 'updated_at': datetime.utcnow()}}
        )
        
        return await self.get_organization(org_id)
    
    # ==================== User Approval System ====================
    
    async def get_pending_users(self, org_id: Optional[str] = None) -> List[Dict]:
        """Get pending user registrations"""
        query = {'status': 'pending'}
        if org_id:
            query['organization_id'] = org_id
        
        users = await self.db.users.find(query).sort('created_at', -1).to_list(100)
        return users
    
    async def approve_user(self, user_id: str, admin_id: str) -> Dict:
        """Approve user registration"""
        await self.db.users.update_one(
            {'id': user_id},
            {'$set': {
                'status': 'approved',
                'is_active': True,
                'approved_at': datetime.utcnow(),
                'approved_by': admin_id
            }}
        )
        
        return await self.db.users.find_one({'id': user_id})
    
    async def reject_user(self, user_id: str, admin_id: str, reason: str = None) -> Dict:
        """Reject user registration"""
        await self.db.users.update_one(
            {'id': user_id},
            {'$set': {
                'status': 'rejected',
                'is_active': False,
                'rejected_at': datetime.utcnow(),
                'rejected_by': admin_id,
                'rejection_reason': reason
            }}
        )
        
        return await self.db.users.find_one({'id': user_id})
    
    async def suspend_user(self, user_id: str, admin_id: str, reason: str = None) -> Dict:
        """Suspend user account"""
        await self.db.users.update_one(
            {'id': user_id},
            {'$set': {
                'status': 'suspended',
                'is_active': False,
                'suspended_at': datetime.utcnow(),
                'suspended_by': admin_id,
                'suspension_reason': reason
            }}
        )
        
        return await self.db.users.find_one({'id': user_id})
    
    # ==================== API Settings ====================
    
    async def create_api_setting(self, org_id: str, name: str, 
                                 api_key: str, provider: str = 'openai') -> Dict:
        """Create API setting"""
        setting = {
            'id': str(uuid.uuid4()),
            'organization_id': org_id,
            'name': name,
            'api_key': api_key,
            'provider': provider,
            'is_active': True,
            'created_at': datetime.utcnow(),
            'usage_count': 0
        }
        
        await self.db.api_settings.insert_one(setting)
        return setting
    
    async def get_api_settings(self, org_id: str) -> List[Dict]:
        """Get all API settings for organization"""
        settings = await self.db.api_settings.find(
            {'organization_id': org_id}
        ).to_list(100)
        
        # Mask API keys
        for setting in settings:
            if setting.get('api_key'):
                setting['api_key_masked'] = setting['api_key'][:8] + '...' + setting['api_key'][-4:]
        
        return settings
    
    async def delete_api_setting(self, setting_id: str) -> bool:
        """Delete API setting"""
        result = await self.db.api_settings.delete_one({'id': setting_id})
        return result.deleted_count > 0
    
    async def generate_api_key(self) -> str:
        """Generate a new API key"""
        return secrets.token_urlsafe(32)
    
    # ==================== Support Tickets ====================
    
    async def create_ticket(self, org_id: str, user_id: str, user_email: str,
                           subject: str, description: str, 
                           priority: str = 'medium', category: str = 'general') -> Dict:
        """Create support ticket"""
        ticket = {
            'id': str(uuid.uuid4()),
            'organization_id': org_id,
            'user_id': user_id,
            'user_email': user_email,
            'subject': subject,
            'description': description,
            'priority': priority,
            'status': 'open',
            'category': category,
            'created_at': datetime.utcnow(),
            'updated_at': datetime.utcnow(),
            'messages': []
        }
        
        await self.db.support_tickets.insert_one(ticket)
        return ticket
    
    async def get_tickets(self, org_id: Optional[str] = None, 
                         user_id: Optional[str] = None,
                         status: Optional[str] = None) -> List[Dict]:
        """Get support tickets"""
        query = {}
        if org_id:
            query['organization_id'] = org_id
        if user_id:
            query['user_id'] = user_id
        if status:
            query['status'] = status
        
        tickets = await self.db.support_tickets.find(query).sort('created_at', -1).to_list(100)
        return tickets
    
    async def get_ticket(self, ticket_id: str) -> Optional[Dict]:
        """Get single ticket"""
        return await self.db.support_tickets.find_one({'id': ticket_id})
    
    async def add_ticket_message(self, ticket_id: str, message: str, 
                                 sender_id: str, is_admin: bool = False) -> Dict:
        """Add message to ticket"""
        msg = {
            'id': str(uuid.uuid4()),
            'sender_id': sender_id,
            'message': message,
            'is_admin': is_admin,
            'created_at': datetime.utcnow()
        }
        
        await self.db.support_tickets.update_one(
            {'id': ticket_id},
            {
                '$push': {'messages': msg},
                '$set': {'updated_at': datetime.utcnow()}
            }
        )
        
        return await self.get_ticket(ticket_id)
    
    async def update_ticket_status(self, ticket_id: str, status: str, 
                                   assigned_to: Optional[str] = None) -> Dict:
        """Update ticket status"""
        updates = {
            'status': status,
            'updated_at': datetime.utcnow()
        }
        
        if assigned_to:
            updates['assigned_to'] = assigned_to
        
        if status == 'resolved':
            updates['resolved_at'] = datetime.utcnow()
        
        await self.db.support_tickets.update_one(
            {'id': ticket_id},
            {'$set': updates}
        )
        
        return await self.get_ticket(ticket_id)
    
    # ==================== Login Logs ====================
    
    async def log_login(self, user_id: str, user_email: str, 
                       ip_address: str, user_agent: str,
                       success: bool, failure_reason: Optional[str] = None,
                       org_id: Optional[str] = None) -> Dict:
        """Log login attempt"""
        log = {
            'id': str(uuid.uuid4()),
            'user_id': user_id,
            'user_email': user_email,
            'organization_id': org_id,
            'ip_address': ip_address,
            'user_agent': user_agent,
            'login_time': datetime.utcnow(),
            'success': success,
            'failure_reason': failure_reason
        }
        
        await self.db.login_logs.insert_one(log)
        return log
    
    async def get_login_logs(self, org_id: Optional[str] = None,
                            user_id: Optional[str] = None,
                            limit: int = 100) -> List[Dict]:
        """Get login logs"""
        query = {}
        if org_id:
            query['organization_id'] = org_id
        if user_id:
            query['user_id'] = user_id
        
        logs = await self.db.login_logs.find(query).sort('login_time', -1).limit(limit).to_list(limit)
        return logs
    
    # ==================== User Settings ====================
    
    async def get_user_settings(self, user_id: str) -> Dict:
        """Get user settings"""
        settings = await self.db.user_settings.find_one({'user_id': user_id})
        
        if not settings:
            # Return default settings
            settings = {
                'user_id': user_id,
                'theme': 'dark',
                'language': 'en',
                'notifications_enabled': True,
                'email_notifications': True,
                'dashboard_layout': {},
                'sidebar_collapsed': False
            }
        
        return settings
    
    async def update_user_settings(self, user_id: str, settings: Dict) -> Dict:
        """Update user settings"""
        settings['user_id'] = user_id
        settings['updated_at'] = datetime.utcnow()
        
        await self.db.user_settings.update_one(
            {'user_id': user_id},
            {'$set': settings},
            upsert=True
        )
        
        return await self.get_user_settings(user_id)
    
    async def update_profile(self, user_id: str, updates: Dict) -> Dict:
        """Update user profile"""
        allowed_fields = ['username', 'phone', 'avatar_url', 'timezone']
        update_data = {k: v for k, v in updates.items() if k in allowed_fields}
        update_data['updated_at'] = datetime.utcnow()
        
        await self.db.users.update_one(
            {'id': user_id},
            {'$set': update_data}
        )
        
        return await self.db.users.find_one({'id': user_id})
    
    # ==================== Billing ====================
    
    async def get_billing_plans(self) -> List[Dict]:
        """Get all billing plans"""
        plans = [
            {
                'id': 'free',
                'name': 'Free',
                'plan_type': 'free',
                'price_monthly': 0,
                'price_yearly': 0,
                'max_users': 3,
                'max_devices': 25,
                'features': ['Basic Monitoring', 'SNMP Support', 'Alerts']
            },
            {
                'id': 'basic',
                'name': 'Basic',
                'plan_type': 'basic',
                'price_monthly': 29,
                'price_yearly': 290,
                'max_users': 10,
                'max_devices': 100,
                'features': ['Everything in Free', 'Multi-vendor Support', 'Reports', 'Backups']
            },
            {
                'id': 'pro',
                'name': 'Pro',
                'plan_type': 'pro',
                'price_monthly': 99,
                'price_yearly': 990,
                'max_users': 50,
                'max_devices': 500,
                'features': ['Everything in Basic', 'AI Features', 'Traffic Analysis', 'Priority Support']
            },
            {
                'id': 'enterprise',
                'name': 'Enterprise',
                'plan_type': 'enterprise',
                'price_monthly': 299,
                'price_yearly': 2990,
                'max_users': 999,
                'max_devices': 9999,
                'features': ['Everything in Pro', 'Custom Branding', 'API Access', 'Dedicated Support']
            }
        ]
        return plans
    
    async def get_subscription(self, org_id: str) -> Optional[Dict]:
        """Get organization subscription"""
        return await self.db.subscriptions.find_one({'organization_id': org_id})
    
    async def create_subscription(self, org_id: str, plan_type: str, 
                                  is_annual: bool = False) -> Dict:
        """Create subscription"""
        plans = await self.get_billing_plans()
        plan = next((p for p in plans if p['plan_type'] == plan_type), plans[0])
        
        subscription = {
            'id': str(uuid.uuid4()),
            'organization_id': org_id,
            'plan_id': plan['id'],
            'plan_type': plan_type,
            'status': 'active',
            'start_date': datetime.utcnow(),
            'is_annual': is_annual,
            'amount_paid': plan['price_yearly'] if is_annual else plan['price_monthly'],
            'next_billing_date': datetime.utcnow() + timedelta(days=365 if is_annual else 30)
        }
        
        await self.db.subscriptions.insert_one(subscription)
        
        # Update organization plan
        await self.db.organizations.update_one(
            {'id': org_id},
            {'$set': {
                'plan': plan_type,
                'max_users': plan['max_users'],
                'max_devices': plan['max_devices'],
                'features_enabled': self._get_default_features(plan_type)
            }}
        )
        
        return subscription
    
    async def get_invoices(self, org_id: str) -> List[Dict]:
        """Get organization invoices"""
        invoices = await self.db.invoices.find(
            {'organization_id': org_id}
        ).sort('created_at', -1).to_list(100)
        return invoices
    
    # ==================== Map Markers ====================
    
    async def add_map_marker(self, org_id: str, name: str, 
                            latitude: float, longitude: float,
                            device_id: Optional[str] = None,
                            marker_type: str = 'device',
                            color: str = '#3b82f6') -> Dict:
        """Add map marker"""
        marker = {
            'id': str(uuid.uuid4()),
            'organization_id': org_id,
            'device_id': device_id,
            'name': name,
            'latitude': latitude,
            'longitude': longitude,
            'marker_type': marker_type,
            'color': color,
            'created_at': datetime.utcnow(),
            'metadata': {}
        }
        
        await self.db.map_markers.insert_one(marker)
        return marker
    
    async def get_map_markers(self, org_id: str) -> List[Dict]:
        """Get map markers for organization"""
        markers = await self.db.map_markers.find(
            {'organization_id': org_id}
        ).to_list(1000)
        return markers
    
    async def update_map_marker(self, marker_id: str, updates: Dict) -> Dict:
        """Update map marker"""
        allowed_fields = ['name', 'latitude', 'longitude', 'marker_type', 'color', 'metadata']
        update_data = {k: v for k, v in updates.items() if k in allowed_fields}
        update_data['updated_at'] = datetime.utcnow()
        
        await self.db.map_markers.update_one(
            {'id': marker_id},
            {'$set': update_data}
        )
        
        return await self.db.map_markers.find_one({'id': marker_id})
    
    async def delete_map_marker(self, marker_id: str) -> bool:
        """Delete map marker"""
        result = await self.db.map_markers.delete_one({'id': marker_id})
        return result.deleted_count > 0
    
    async def get_map_settings(self, org_id: str) -> Dict:
        """Get map settings"""
        settings = await self.db.map_settings.find_one({'organization_id': org_id})
        
        if not settings:
            settings = {
                'organization_id': org_id,
                'default_center': {'lat': 0, 'lng': 0},
                'default_zoom': 10,
                'map_style': 'dark',
                'show_device_status': True,
                'cluster_markers': True
            }
        
        return settings
    
    async def update_map_settings(self, org_id: str, settings: Dict) -> Dict:
        """Update map settings"""
        settings['organization_id'] = org_id
        settings['updated_at'] = datetime.utcnow()
        
        await self.db.map_settings.update_one(
            {'organization_id': org_id},
            {'$set': settings},
            upsert=True
        )
        
        return await self.get_map_settings(org_id)
    
    # ==================== Data Import ====================
    
    async def create_import_job(self, org_id: str, user_id: str,
                               file_name: str, file_type: str,
                               import_type: str) -> Dict:
        """Create data import job"""
        job = {
            'id': str(uuid.uuid4()),
            'organization_id': org_id,
            'user_id': user_id,
            'file_name': file_name,
            'file_type': file_type,
            'import_type': import_type,
            'status': 'pending',
            'total_records': 0,
            'processed_records': 0,
            'failed_records': 0,
            'errors': [],
            'started_at': datetime.utcnow()
        }
        
        await self.db.import_jobs.insert_one(job)
        return job
    
    async def get_import_jobs(self, org_id: str) -> List[Dict]:
        """Get import jobs for organization"""
        jobs = await self.db.import_jobs.find(
            {'organization_id': org_id}
        ).sort('started_at', -1).to_list(50)
        return jobs
    
    # ==================== App Updates ====================
    
    async def check_for_updates(self, current_version: str) -> Optional[Dict]:
        """Check for app updates"""
        update = await self.db.app_updates.find_one(
            {'version': {'$gt': current_version}},
            sort=[('released_at', -1)]
        )
        return update
    
    async def get_latest_update(self) -> Optional[Dict]:
        """Get latest app update"""
        return await self.db.app_updates.find_one(
            {},
            sort=[('released_at', -1)]
        )
    
    # ==================== Dashboard Stats ====================
    
    async def get_admin_dashboard_stats(self, org_id: Optional[str] = None) -> Dict:
        """Get comprehensive admin dashboard stats"""
        query = {}
        if org_id:
            query['organization_id'] = org_id
        
        # User stats
        total_users = await self.db.users.count_documents(query)
        active_users = await self.db.users.count_documents({**query, 'is_active': True})
        pending_users = await self.db.users.count_documents({**query, 'status': 'pending'})
        
        # Device stats
        total_devices = await self.db.devices.count_documents(query)
        online_devices = await self.db.devices.count_documents({**query, 'status': 'online'})
        
        # Ticket stats
        open_tickets = await self.db.support_tickets.count_documents({**query, 'status': 'open'})
        
        # Recent logins
        recent_logins = await self.db.login_logs.find(query).sort('login_time', -1).limit(5).to_list(5)
        
        # Organizations (super admin only)
        total_orgs = 0
        if not org_id:
            total_orgs = await self.db.organizations.count_documents({})
        
        return {
            'users': {
                'total': total_users,
                'active': active_users,
                'pending': pending_users
            },
            'devices': {
                'total': total_devices,
                'online': online_devices,
                'offline': total_devices - online_devices
            },
            'tickets': {
                'open': open_tickets
            },
            'organizations': {
                'total': total_orgs
            },
            'recent_logins': recent_logins,
            'generated_at': datetime.utcnow().isoformat()
        }


# Global instance
admin_panel_manager = None
