"""
REST API for web dashboard
"""
import os
import logging
import time
from datetime import datetime
from pathlib import Path
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:
            logger.info(f"Web Dashboard API control_video called - action: {action}, kwargs: {kwargs}")
            success = False
            
            if action == "play":
                file_path = kwargs.get("file_path", "")
                template = kwargs.get("template", "news_template")
                overlay_data = kwargs.get("overlay_data", {})
                
                # Convert relative path to absolute path
                if file_path and not os.path.isabs(file_path):
                    # Get the project root directory (where main.py is located)
                    project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
                    absolute_file_path = os.path.join(project_root, file_path)
                    logger.info(f"Converting relative path '{file_path}' to absolute path '{absolute_file_path}'")
                    file_path = absolute_file_path
                else:
                    logger.info(f"Using provided absolute path: {file_path}")
                
                # Verify file exists before sending to Qt player
                if file_path and not os.path.exists(file_path):
                    logger.error(f"Video file does not exist: {file_path}")
                    return {"error": f"Video file not found: {file_path}"}
                
                logger.info(f"Creating VIDEO_PLAY message - file_path: {file_path}, template: {template}")
                message = MessageBuilder.video_play(
                    sender="web_dashboard",
                    file_path=file_path,
                    template=template,
                    overlay_data=overlay_data
                )
                message.recipient = "qt_player"
                
                logger.info(f"Publishing VIDEO_PLAY message to qt_player")
                logger.info(f"Message data: {message.data}")
                logger.info(f"Message bus registered components: {list(self.message_bus._queues.keys()) if hasattr(self.message_bus, '_queues') else 'Unknown'}")
                
                publish_result = self.message_bus.publish(message)
                logger.info(f"Message bus publish result: {publish_result}")
                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 successfully: {action}")
                return {"success": True, "action": action}
            else:
                logger.error("Failed to send video control command")
                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 and load specific template"""
        try:
            # Send template change message to load the specific template
            template_data = data.copy()
            template_data['reload_template'] = True  # Flag to trigger template reload
            template_data['load_specific_template'] = template  # Specific template to load
            
            message = MessageBuilder.template_change(
                sender="web_dashboard",
                template_name=template,
                template_data=template_data
            )
            message.recipient = "qt_player"
            self.message_bus.publish(message)
            
            # Also send a separate overlay update message to ensure data is updated
            overlay_message = MessageBuilder.overlay_update(
                sender="web_dashboard",
                overlay_data=data
            )
            overlay_message.recipient = "qt_player"
            self.message_bus.publish(overlay_message)
            
            logger.info(f"Overlay update and template load sent: {template}")
            return {"success": True, "template": template, "loaded": True}
            
        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 from both built-in and uploaded directories"""
        try:
            from pathlib import Path
            
            # Get built-in templates directory
            builtin_templates_dir = Path(__file__).parent.parent / "qt_player" / "templates"
            
            # Get persistent uploaded templates directory
            uploaded_templates_dir = self._get_persistent_templates_dir()
            
            template_list = []
            templates_seen = set()
            
            # First scan uploaded templates (these take priority)
            if uploaded_templates_dir.exists():
                uploaded_files = list(uploaded_templates_dir.glob("*.html"))
                for html_file in uploaded_files:
                    template_name = html_file.stem
                    template_list.append({
                        "name": template_name,
                        "filename": html_file.name,
                        "display_name": template_name.replace("_", " ").title(),
                        "source": "uploaded",
                        "can_delete": True
                    })
                    templates_seen.add(template_name)
                logger.info(f"Found {len(uploaded_files)} uploaded templates in {uploaded_templates_dir}")
            
            # Then scan built-in templates (only add if not already seen from uploads)
            if builtin_templates_dir.exists():
                builtin_files = list(builtin_templates_dir.glob("*.html"))
                for html_file in builtin_files:
                    template_name = html_file.stem
                    if template_name not in templates_seen:
                        template_list.append({
                            "name": template_name,
                            "filename": html_file.name,
                            "display_name": template_name.replace("_", " ").title(),
                            "source": "builtin",
                            "can_delete": False
                        })
                        templates_seen.add(template_name)
                logger.info(f"Found {len(builtin_files)} built-in templates in {builtin_templates_dir}")
            else:
                logger.warning(f"Built-in templates directory not found: {builtin_templates_dir}")
            
            # Ensure default template is always available
            if not any(t["name"] == "default" for t in template_list):
                template_list.insert(0, {
                    "name": "default",
                    "filename": "default.html",
                    "display_name": "Default",
                    "source": "builtin",
                    "can_delete": False
                })
            
            # Sort templates: uploaded first, then built-in, with default always first
            template_list.sort(key=lambda t: (
                0 if t["name"] == "default" else 1,  # Default first
                1 if t["source"] == "builtin" else 0,  # Uploaded before built-in
                t["name"]  # Alphabetical within each group
            ))
            
            return {"templates": template_list}
            
        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"],
                    "role": user.get("role", "normal"),  # Include role field
                    "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, role: str = 'normal') -> 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, role)
            
            if user:
                return {
                    "success": True,
                    "user": {
                        "id": user["id"],
                        "username": user["username"],
                        "email": user["email"],
                        "is_admin": user["is_admin"],
                        "role": user.get("role", "normal")
                    }
                }
            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, role: str = 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, role)
            
            if user:
                return {
                    "success": True,
                    "user": {
                        "id": user["id"],
                        "username": user["username"],
                        "email": user["email"],
                        "is_admin": user["is_admin"],
                        "role": user.get("role", "normal")
                    }
                }
            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 web interface (will be converted to absolute when playing)
            relative_path = os.path.join('uploads', unique_filename)
            
            logger.info(f"Video uploaded successfully")
            logger.info(f"Saved to: {file_path}")
            logger.info(f"Relative path for web interface: {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)}
    
    def _get_persistent_templates_dir(self) -> Path:
        """Get persistent templates directory for user uploads"""
        try:
            import platform
            from pathlib import Path
            
            system = platform.system()
            
            if system == "Windows":
                # Use AppData/Roaming on Windows
                app_data = os.getenv('APPDATA', os.path.expanduser('~'))
                templates_dir = Path(app_data) / "MbetterClient" / "templates"
            elif system == "Darwin":  # macOS
                # Use ~/Library/Application Support on macOS
                templates_dir = Path.home() / "Library" / "Application Support" / "MbetterClient" / "templates"
            else:  # Linux and other Unix-like systems
                # Use ~/.config on Linux
                config_home = os.getenv('XDG_CONFIG_HOME', str(Path.home() / ".config"))
                templates_dir = Path(config_home) / "MbetterClient" / "templates"
            
            logger.debug(f"Persistent templates directory: {templates_dir}")
            return templates_dir
                
        except Exception as e:
            logger.error(f"Failed to determine persistent templates directory: {e}")
            # Fallback to local directory
            return Path.cwd() / "user_templates"
    
    def upload_template(self, file_data, template_name: str = None) -> Dict[str, Any]:
        """Upload template file to persistent directory"""
        try:
            from werkzeug.utils import secure_filename
            
            # Get persistent templates directory
            templates_dir = self._get_persistent_templates_dir()
            templates_dir.mkdir(parents=True, exist_ok=True)
            
            # Secure the filename
            filename = secure_filename(file_data.filename)
            if not filename:
                return {"error": "Invalid filename"}
            
            # Ensure .html extension
            if not filename.lower().endswith('.html'):
                filename += '.html'
            
            # Use provided template name or derive from filename
            if template_name:
                filename = secure_filename(template_name)
                if not filename.lower().endswith('.html'):
                    filename += '.html'
            
            # Save to persistent templates directory
            file_path = templates_dir / filename
            file_data.save(str(file_path))
            
            logger.info(f"Template uploaded successfully: {file_path}")
            
            return {
                "success": True,
                "message": "Template uploaded successfully",
                "filename": filename,
                "template_name": Path(filename).stem
            }
            
        except Exception as e:
            logger.error(f"Template upload error: {e}")
            return {"error": str(e)}
    
    def delete_template(self, template_name: str) -> Dict[str, Any]:
        """Delete uploaded template file"""
        try:
            # Only allow deletion of uploaded templates, not built-in ones
            templates_dir = self._get_persistent_templates_dir()
            
            # Add .html extension if not present
            if not template_name.endswith('.html'):
                template_name += '.html'
            
            template_path = templates_dir / template_name
            
            if not template_path.exists():
                return {"error": "Template not found in uploaded templates"}
            
            # Delete the file
            template_path.unlink()
            
            logger.info(f"Template deleted: {template_path}")
            
            return {
                "success": True,
                "message": "Template deleted successfully",
                "template_name": Path(template_name).stem
            }
            
        except Exception as e:
            logger.error(f"Template 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
