"""
REST API for web dashboard
"""

import logging
import time
from datetime import datetime
from typing import Dict, Any, Optional, List
from flask import request, jsonify, g

from ..database.manager import DatabaseManager
from ..config.manager import ConfigManager
from ..core.message_bus import MessageBus, MessageBuilder, MessageType, Message

logger = logging.getLogger(__name__)


class DashboardAPI:
    """REST API endpoints for the dashboard"""
    
    def __init__(self, db_manager: DatabaseManager, config_manager: ConfigManager, 
                 message_bus: MessageBus):
        self.db_manager = db_manager
        self.config_manager = config_manager
        self.message_bus = message_bus
        
        logger.info("DashboardAPI initialized")
    
    def get_system_status(self) -> Dict[str, Any]:
        """Get system status"""
        try:
            # Get configuration status
            config_status = self.config_manager.validate_configuration()
            
            # Get database status
            db_status = self.db_manager.get_connection_status()
            
            # Get component status (cached or from message bus)
            components_status = self._get_components_status()
            
            return {
                "status": "online",
                "timestamp": datetime.utcnow().isoformat(),
                "uptime": time.time(),  # Would be actual uptime in production
                "config": config_status,
                "database": db_status,
                "components": components_status
            }
            
        except Exception as e:
            logger.error(f"Failed to get system status: {e}")
            return {
                "status": "error",
                "error": str(e),
                "timestamp": datetime.utcnow().isoformat()
            }
    
    def get_video_status(self) -> Dict[str, Any]:
        """Get video player status"""
        try:
            # Request status from video player
            status_request = Message(
                type=MessageType.STATUS_REQUEST,
                sender="web_dashboard",
                recipient="qt_player",
                data={}
            )
            self.message_bus.publish(status_request)
            
            # For now, return basic status
            # In full implementation, would wait for response or use cached status
            return {
                "player_status": "unknown",
                "current_file": None,
                "current_template": "news_template",
                "position": 0,
                "duration": 0,
                "volume": 100,
                "fullscreen": False
            }
            
        except Exception as e:
            logger.error(f"Failed to get video status: {e}")
            return {"error": str(e)}
    
    def control_video(self, action: str, **kwargs) -> Dict[str, Any]:
        """Control video player"""
        try:
            success = False
            
            if action == "play":
                file_path = kwargs.get("file_path", "")
                template = kwargs.get("template", "news_template")
                overlay_data = kwargs.get("overlay_data", {})
                
                message = MessageBuilder.video_play(
                    sender="web_dashboard",
                    file_path=file_path,
                    template=template,
                    overlay_data=overlay_data
                )
                message.recipient = "qt_player"
                self.message_bus.publish(message)
                success = True
                
            elif action == "pause":
                message = Message(
                    type=MessageType.VIDEO_PAUSE,
                    sender="web_dashboard",
                    recipient="qt_player",
                    data={}
                )
                self.message_bus.publish(message)
                success = True
                
            elif action == "stop":
                message = Message(
                    type=MessageType.VIDEO_STOP,
                    sender="web_dashboard",
                    recipient="qt_player",
                    data={}
                )
                self.message_bus.publish(message)
                success = True
                
            elif action == "seek":
                position = kwargs.get("position", 0)
                message = Message(
                    type=MessageType.VIDEO_SEEK,
                    sender="web_dashboard",
                    recipient="qt_player",
                    data={"position": position}
                )
                self.message_bus.publish(message)
                success = True
                
            elif action == "volume":
                volume = kwargs.get("volume", 100)
                message = Message(
                    type=MessageType.VIDEO_VOLUME,
                    sender="web_dashboard",
                    recipient="qt_player",
                    data={"volume": volume}
                )
                self.message_bus.publish(message)
                success = True
                
            elif action == "fullscreen":
                fullscreen = kwargs.get("fullscreen", True)
                message = Message(
                    type=MessageType.VIDEO_FULLSCREEN,
                    sender="web_dashboard",
                    recipient="qt_player",
                    data={"fullscreen": fullscreen}
                )
                self.message_bus.publish(message)
                success = True
                
            else:
                return {"error": f"Unknown action: {action}"}
            
            if success:
                logger.info(f"Video control command sent: {action}")
                return {"success": True, "action": action}
            else:
                return {"error": "Failed to send command"}
                
        except Exception as e:
            logger.error(f"Video control error: {e}")
            return {"error": str(e)}
    
    def update_overlay(self, template: str, data: Dict[str, Any]) -> Dict[str, Any]:
        """Update video overlay"""
        try:
            message = MessageBuilder.template_change(
                sender="web_dashboard",
                template_name=template,
                template_data=data
            )
            message.recipient = "qt_player"
            self.message_bus.publish(message)
            
            logger.info(f"Overlay update sent: {template}")
            return {"success": True, "template": template}
            
        except Exception as e:
            logger.error(f"Overlay update error: {e}")
            return {"error": str(e)}
    
    def get_templates(self) -> Dict[str, Any]:
        """Get available overlay templates"""
        try:
            # This would normally query the template system
            templates = {
                "news_template": {
                    "name": "News Template",
                    "description": "Breaking news with scrolling text",
                    "fields": ["headline", "ticker_text", "logo_url"]
                },
                "sports_template": {
                    "name": "Sports Template", 
                    "description": "Sports scores and updates",
                    "fields": ["team1", "team2", "score1", "score2", "event"]
                },
                "simple_template": {
                    "name": "Simple Template",
                    "description": "Basic text overlay",
                    "fields": ["title", "subtitle", "text"]
                }
            }
            
            return {"templates": templates}
            
        except Exception as e:
            logger.error(f"Failed to get templates: {e}")
            return {"error": str(e)}
    
    def get_configuration(self, section: Optional[str] = None) -> Dict[str, Any]:
        """Get configuration data"""
        try:
            if section:
                config_data = self.config_manager.get_section_config(section)
                return {"section": section, "config": config_data}
            else:
                all_config = self.config_manager.get_all_config()
                return {"config": all_config}
                
        except Exception as e:
            logger.error(f"Failed to get configuration: {e}")
            return {"error": str(e)}
    
    def update_configuration(self, section: str, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """Update configuration"""
        try:
            # Update configuration
            success = self.config_manager.update_section(section, config_data)
            
            if success:
                # Notify other components of configuration change
                message = Message(
                    type=MessageType.CONFIG_UPDATE,
                    sender="web_dashboard",
                    data={
                        "config_section": section,
                        "config_data": config_data
                    }
                )
                self.message_bus.publish(message)
                
                logger.info(f"Configuration updated: {section}")
                return {"success": True, "section": section}
            else:
                return {"error": "Failed to update configuration"}
                
        except Exception as e:
            logger.error(f"Configuration update error: {e}")
            return {"error": str(e)}
    
    def get_logs(self, level: str = "INFO", limit: int = 100) -> Dict[str, Any]:
        """Get application logs"""
        try:
            # This would normally read from log files or database
            # For now, return placeholder data
            logs = [
                {
                    "timestamp": datetime.utcnow().isoformat(),
                    "level": "INFO",
                    "component": "web_dashboard",
                    "message": "Dashboard started successfully"
                },
                {
                    "timestamp": datetime.utcnow().isoformat(),
                    "level": "INFO", 
                    "component": "qt_player",
                    "message": "Video player initialized"
                }
            ]
            
            return {"logs": logs[:limit]}
            
        except Exception as e:
            logger.error(f"Failed to get logs: {e}")
            return {"error": str(e)}
    
    def get_users(self) -> Dict[str, Any]:
        """Get all users (admin only)"""
        try:
            users = self.db_manager.get_all_users()
            user_list = [
                {
                    "id": user["id"],
                    "username": user["username"],
                    "email": user["email"],
                    "is_admin": user["is_admin"],
                    "created_at": user["created_at"].isoformat() if user["created_at"] else None,
                    "last_login": user["last_login"].isoformat() if user["last_login"] else None
                }
                for user in users
            ]
            
            return {"users": user_list}
            
        except Exception as e:
            logger.error(f"Failed to get users: {e}")
            return {"error": str(e)}
    
    def create_user(self, username: str, email: str, password: str, 
                   is_admin: bool = False) -> Dict[str, Any]:
        """Create new user (admin only)"""
        try:
            from .auth import AuthManager
            
            # Get auth manager from Flask g context
            auth_manager = g.get('auth_manager')
            if not auth_manager:
                return {"error": "Auth manager not available"}
            
            user = auth_manager.create_user(username, email, password, is_admin)
            
            if user:
                return {
                    "success": True,
                    "user": {
                        "id": user["id"],
                        "username": user["username"],
                        "email": user["email"],
                        "is_admin": user["is_admin"]
                    }
                }
            else:
                return {"error": "Failed to create user"}
                
        except Exception as e:
            logger.error(f"User creation error: {e}")
            return {"error": str(e)}
    
    def update_user(self, user_id: int, username: str = None, email: str = None,
                   password: str = None, is_admin: bool = None) -> Dict[str, Any]:
        """Update user (admin only)"""
        try:
            from .auth import AuthManager
            
            # Get auth manager from Flask g context
            auth_manager = g.get('auth_manager')
            if not auth_manager:
                return {"error": "Auth manager not available"}
            
            user = auth_manager.update_user(user_id, username, email, password, is_admin)
            
            if user:
                return {
                    "success": True,
                    "user": {
                        "id": user["id"],
                        "username": user["username"],
                        "email": user["email"],
                        "is_admin": user["is_admin"]
                    }
                }
            else:
                return {"error": "Failed to update user"}
                
        except Exception as e:
            logger.error(f"User update error: {e}")
            return {"error": str(e)}
    
    def delete_user(self, user_id: int) -> Dict[str, Any]:
        """Delete user (admin only)"""
        try:
            success = self.db_manager.delete_user(user_id)
            
            if success:
                logger.info(f"User deleted: {user_id}")
                return {"success": True}
            else:
                return {"error": "Failed to delete user"}
                
        except Exception as e:
            logger.error(f"User deletion error: {e}")
            return {"error": str(e)}
    
    def get_api_tokens(self, user_id: int) -> List[Dict[str, Any]]:
        """Get API tokens for user"""
        try:
            from .auth import AuthManager
            
            auth_manager = g.get('auth_manager')
            if not auth_manager:
                return {"error": "Auth manager not available"}
            
            tokens = auth_manager.list_user_tokens(user_id)
            
            # Add token preview for each token (first 8 chars + ... + last 4 chars)
            for token_data in tokens:
                # We don't store the actual token, so create a fake preview
                token_data['token_preview'] = f"{'*' * 8}...{'*' * 4}"
                # We can't show the actual token since it's hashed
                token_data['token'] = "[Hidden - Token only shown once during creation]"
            
            return tokens
            
        except Exception as e:
            logger.error(f"Failed to get API tokens: {e}")
            return []
    
    def create_api_token(self, user_id: int, token_name: str, 
                        expires_hours: int = 8760) -> Dict[str, Any]:
        """Create API token"""
        try:
            from .auth import AuthManager
            
            auth_manager = g.get('auth_manager')
            if not auth_manager:
                return {"error": "Auth manager not available"}
            
            result = auth_manager.create_api_token(user_id, token_name, expires_hours)
            
            if result:
                token, token_data = result
                return {
                    "success": True,
                    "token": token,
                    "token_info": {
                        "id": token_data['id'],
                        "name": token_data['name'],
                        "expires_at": token_data['expires_at'].isoformat() if isinstance(token_data['expires_at'], datetime) else token_data['expires_at']
                    }
                }
            else:
                return {"error": "Failed to create API token"}
                
        except Exception as e:
            logger.error(f"API token creation error: {e}")
            return {"error": str(e)}
    
    def revoke_api_token(self, user_id: int, token_id: int) -> Dict[str, Any]:
        """Revoke API token"""
        try:
            from .auth import AuthManager
            
            auth_manager = g.get('auth_manager')
            if not auth_manager:
                return {"error": "Auth manager not available"}
            
            success = auth_manager.revoke_api_token_by_id(token_id, user_id)
            
            if success:
                return {"success": True}
            else:
                return {"error": "Failed to revoke token"}
                
        except Exception as e:
            logger.error(f"API token revocation error: {e}")
            return {"error": str(e)}
    
    def _get_components_status(self) -> Dict[str, Any]:
        """Get status of all components"""
        # This would normally maintain a cache of component status
        # or query components through message bus
        return {
            "qt_player": "unknown",
            "web_dashboard": "running", 
            "api_client": "unknown",
            "message_bus": "running"
        }
    
    def send_test_message(self, recipient: str, message_type: str, 
                         data: Dict[str, Any]) -> Dict[str, Any]:
        """Send test message to component (admin only)"""
        try:
            # Map string message types to enum
            type_mapping = {
                "video_play": MessageType.VIDEO_PLAY,
                "video_pause": MessageType.VIDEO_PAUSE,
                "video_stop": MessageType.VIDEO_STOP,
                "config_update": MessageType.CONFIG_UPDATE,
                "system_status": MessageType.SYSTEM_STATUS,
            }
            
            msg_type = type_mapping.get(message_type)
            if not msg_type:
                return {"error": f"Unknown message type: {message_type}"}
            
            message = Message(
                type=msg_type,
                sender="web_dashboard",
                recipient=recipient,
                data=data
            )
            
            self.message_bus.publish(message)
            
            logger.info(f"Test message sent: {message_type} to {recipient}")
            return {"success": True, "message_type": message_type, "recipient": recipient}
            
        except Exception as e:
            logger.error(f"Test message error: {e}")
            return {"error": str(e)}
    
    def upload_video(self, file_data, template: str) -> Dict[str, Any]:
        """Handle video upload"""
        try:
            import os
            import uuid
            from werkzeug.utils import secure_filename
            
            # Create uploads directory if it doesn't exist
            upload_dir = os.path.join(os.path.dirname(__file__), '..', '..', 'uploads')
            os.makedirs(upload_dir, exist_ok=True)
            
            # Generate unique filename
            filename = secure_filename(file_data.filename)
            if not filename:
                filename = str(uuid.uuid4()) + ".mp4"
            
            # Add timestamp to filename to make it unique
            name, ext = os.path.splitext(filename)
            unique_filename = f"{name}_{int(time.time())}{ext}"
            
            # Save file
            file_path = os.path.join(upload_dir, unique_filename)
            file_data.save(file_path)
            
            # Return relative path for the Qt player
            relative_path = os.path.join('uploads', unique_filename)
            
            logger.info(f"Video uploaded: {relative_path}")
            return {
                "success": True,
                "filename": relative_path,
                "message": "Video uploaded successfully"
            }
            
        except Exception as e:
            logger.error(f"Video upload error: {e}")
            return {"error": str(e)}
    
    def delete_video(self, filename: str) -> Dict[str, Any]:
        """Delete uploaded video"""
        try:
            import os
            
            # Construct full path
            file_path = os.path.join(os.path.dirname(__file__), '..', '..', filename)
            
            # Check if file exists
            if os.path.exists(file_path):
                os.remove(file_path)
                logger.info(f"Video deleted: {filename}")
                return {"success": True, "message": "Video deleted successfully"}
            else:
                return {"error": "File not found"}
                
        except Exception as e:
            logger.error(f"Video deletion error: {e}")
            return {"error": str(e)}


# Route functions for Flask
def get_config_section(section):
    """Get configuration section"""
    try:
        api = g.get('api')
        if not api:
            return jsonify({"error": "API not available"}), 500
            
        result = api.get_configuration(section)
        if "error" in result:
            return jsonify(result), 500
        else:
            return jsonify(result)
            
    except Exception as e:
        logger.error(f"Route get_config_section error: {e}")
        return jsonify({"error": str(e)}), 500


def update_config_section(section):
    """Update configuration section"""
    try:
        api = g.get('api')
        if not api:
            return jsonify({"error": "API not available"}), 500
            
        data = request.get_json() or {}
        result = api.update_configuration(section, data)
        
        if "error" in result:
            return jsonify(result), 500
        else:
            return jsonify(result)
            
    except Exception as e:
        logger.error(f"Route update_config_section error: {e}")
        return jsonify({"error": str(e)}), 500