"""
Instance Manager - Manages OpenVoiceUI instances
Handles provisioning, starting, stopping, and monitoring instances
"""
import os
import subprocess
import docker
import logging
from datetime import datetime
from app import db
from app.models import Instance

logger = logging.getLogger(__name__)


class InstanceManager:
    """Manages voice AI instance lifecycle"""

    def __init__(self):
        self.docker_client = None
        try:
            self.docker_client = docker.from_env()
        except Exception as e:
            logger.warning(f"Docker not available: {e}")

    def create_instance(self, user_id, name, description='', config=None):
        """Create and provision a new instance"""
        from app.models import Instance, User

        # Get user
        user = User.query.get(user_id)
        if not user:
            raise ValueError(f"User {user_id} not found")

        # Generate instance IDs
        instance_id = Instance.generate_instance_id()
        subdomain = Instance.generate_subdomain(name)

        # Get next available port
        last_instance = db.session.query(Instance).order_by(
            Instance.port.desc()
        ).first()
        port = (last_instance.port + 1) if last_instance else 4500

        # Create instance record
        instance = Instance(
            instance_id=instance_id,
            user_id=user_id,
            name=name,
            subdomain=subdomain,
            description=description,
            port=port,
            status='provisioning',
            config=config or {}
        )

        db.session.add(instance)
        db.session.commit()

        # Provision the instance
        try:
            self._provision_instance(instance)
            instance.status = 'running'
            db.session.commit()
            logger.info(f"Instance {instance_id} provisioned successfully")
        except Exception as e:
            instance.status = 'error'
            db.session.commit()
            logger.error(f"Failed to provision instance {instance_id}: {e}")
            raise

        return instance

    def _provision_instance(self, instance):
        """Provision instance resources"""
        # Create instance directory
        instance_dir = f"/home/ashraffarid2010/wakelai.com/voice_engine/instances/{instance.instance_id}"
        os.makedirs(instance_dir, exist_ok=True)

        # Create configuration file
        config_file = os.path.join(instance_dir, '.env')
        with open(config_file, 'w') as f:
            f.write(f"""# Instance Configuration for {instance.name}
INSTANCE_ID={instance.instance_id}
INSTANCE_PORT={instance.port}
INSTANCE_SUBDOMAIN={instance.subdomain}

# LLM Configuration
CLAWDBOT_AUTH_TOKEN={os.getenv('CLAWDBOT_AUTH_TOKEN')}
ANTHROPIC_API_KEY={os.getenv('ANTHROPIC_API_KEY')}

# TTS Configuration
TTS_PROVIDER={instance.voice_provider}
GROQ_API_KEY={os.getenv('GROQ_API_KEY')}
ELEVENLABS_API_KEY={os.getenv('ELEVENLABS_API_KEY')}

# STT Configuration
STT_PROVIDER={os.getenv('STT_PROVIDER', 'web_speech')}
DEEPGRAM_API_KEY={os.getenv('DEEPGRAM_API_KEY')}
""")

        # If Docker is available, create container
        if self.docker_client:
            self._create_docker_container(instance, instance_dir)

    def _create_docker_container(self, instance, instance_dir):
        """Create Docker container for instance"""
        container_name = f"wakelai-{instance.instance_id}"

        # Check if container already exists
        try:
            existing = self.docker_client.containers.get(container_name)
            existing.remove(force=True)
        except:
            pass

        # Create and start container
        try:
            container = self.docker_client.containers.run(
                image="openvoiceui:latest",  # TODO: Use actual image
                name=container_name,
                detach=True,
                ports={5001: instance.port},
                volumes={
                    instance_dir: {'bind': '/app/config', 'mode': 'rw'}
                },
                environment={
                    'INSTANCE_ID': instance.instance_id,
                    'PORT': 5001,
                    'CLAWDBOT_AUTH_TOKEN': os.getenv('CLAWDBOT_AUTH_TOKEN')
                },
                restart_policy={"Name": "unless-stopped"}
            )

            instance.container_id = container.id
            logger.info(f"Created Docker container {container_name}")
        except Exception as e:
            logger.error(f"Failed to create Docker container: {e}")
            raise

    def start_instance(self, instance):
        """Start a stopped instance"""
        if instance.container_id and self.docker_client:
            try:
                container = self.docker_client.containers.get(instance.container_id)
                container.start()
                instance.status = 'running'
                logger.info(f"Started instance {instance.instance_id}")
            except Exception as e:
                logger.error(f"Failed to start container: {e}")
                raise
        else:
            # Start without Docker (development)
            instance.status = 'running'

        db.session.commit()

    def stop_instance(self, instance):
        """Stop a running instance"""
        if instance.container_id and self.docker_client:
            try:
                container = self.docker_client.containers.get(instance.container_id)
                container.stop()
                instance.status = 'stopped'
                logger.info(f"Stopped instance {instance.instance_id}")
            except Exception as e:
                logger.error(f"Failed to stop container: {e}")
                raise
        else:
            instance.status = 'stopped'

        db.session.commit()

    def restart_instance(self, instance):
        """Restart an instance"""
        self.stop_instance(instance)
        self.start_instance(instance)

    def get_instance_logs(self, instance, lines=100):
        """Get instance logs"""
        if instance.container_id and self.docker_client:
            try:
                container = self.docker_client.containers.get(instance.container_id)
                logs = container.logs(tail=lines).decode('utf-8')
                return logs.split('\n')
            except Exception as e:
                logger.error(f"Failed to get logs: {e}")
                return []

        # Return empty array if no Docker
        return []

    def check_health(self, instance):
        """Check instance health"""
        health = {
            'status': instance.status,
            'healthy': False,
            'uptime': None,
            'memory_usage': None,
            'cpu_usage': None
        }

        if instance.container_id and self.docker_client:
            try:
                container = self.docker_client.containers.get(instance.container_id)
                container_status = container.status

                health['status'] = container_status
                health['healthy'] = container_status == 'running'

                # Get stats
                stats = container.stats(stream=False)
                if stats:
                    # Calculate CPU usage
                    cpu_delta = stats['cpu_stats']['cpu_usage']['total_usage'] - \
                               stats['precpu_stats']['cpu_usage']['total_usage']
                    system_delta = stats['cpu_stats']['system_cpu_usage'] - \
                                  stats['precpu_stats']['system_cpu_usage']
                    health['cpu_usage'] = (cpu_delta / system_delta) * 100 if system_delta > 0 else 0

                    # Memory usage
                    memory_usage = stats['memory_stats'].get('usage', 0)
                    health['memory_usage'] = memory_usage / (1024 * 1024)  # Convert to MB

            except Exception as e:
                logger.error(f"Failed to check health: {e}")
                health['healthy'] = False

        return health

    def delete_instance(self, instance):
        """Delete instance and cleanup resources"""
        # Stop and remove container
        if instance.container_id and self.docker_client:
            try:
                container = self.docker_client.containers.get(instance.container_id)
                container.remove(force=True)
                logger.info(f"Removed container for instance {instance.instance_id}")
            except Exception as e:
                logger.error(f"Failed to remove container: {e}")

        # Remove instance directory
        instance_dir = f"/home/ashraffarid2010/wakelai.com/voice_engine/instances/{instance.instance_id}"
        try:
            import shutil
            if os.path.exists(instance_dir):
                shutil.rmtree(instance_dir)
                logger.info(f"Removed instance directory {instance_dir}")
        except Exception as e:
            logger.error(f"Failed to remove directory: {e}")


# Singleton instance
_instance_manager = None


def get_instance_manager():
    """Get instance manager singleton"""
    global _instance_manager
    if _instance_manager is None:
        _instance_manager = InstanceManager()
    return _instance_manager
