"""
Daemon Manager for SoraCLI Background Mode.

Orchestrates the background weather animation service using tmux.
"""

import os
import sys
import time
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Optional

from soracli.config import load_config, SoraConfig
from soracli.daemon.tmux_controller import TmuxController, TmuxError


@dataclass
class DaemonStatus:
    """Status information for the SoraCLI daemon."""
    running: bool
    session_name: str
    attached: bool = False
    animation_running: bool = False
    location: Optional[str] = None
    theme: Optional[str] = None
    uptime: Optional[str] = None
    pane_count: int = 0


class DaemonError(Exception):
    """Exception raised for daemon-related errors."""
    pass


class DaemonManager:
    """
    Manager for SoraCLI daemon mode.
    
    Handles starting, stopping, and monitoring the background
    weather animation service.
    """
    
    SESSION_NAME = "sora_bg"
    CONFIG_DIR = Path.home() / ".config" / "soracli"
    STARTUP_SCRIPT = CONFIG_DIR / "startup.sh"
    PID_FILE = CONFIG_DIR / "daemon.pid"
    
    def __init__(self):
        self.tmux = TmuxController()
        self.config = load_config()
    
    def check_tmux(self) -> bool:
        """Check if tmux is available."""
        return self.tmux.is_tmux_available()
    
    def is_running(self) -> bool:
        """Check if daemon is currently running."""
        return self.tmux.session_exists(self.SESSION_NAME)
    
    def attach(self) -> None:
        """Attach to the running daemon session."""
        self.tmux.attach_session(self.SESSION_NAME)
    
    def check_requirements(self) -> tuple[bool, str]:
        """
        Check if all requirements for daemon mode are met.
        
        Returns:
            Tuple of (success, message)
        """
        # Check tmux
        if not self.tmux.is_tmux_available():
            return False, (
                "tmux is not installed.\n"
                "Install with:\n"
                "  - Linux (Debian/Ubuntu): sudo apt install tmux\n"
                "  - Linux (Fedora): sudo dnf install tmux\n"
                "  - macOS: brew install tmux\n"
                "  - Windows (WSL): sudo apt install tmux"
            )
        
        # Check if we're already inside tmux
        if os.environ.get('TMUX'):
            return True, "Running inside tmux session"
        
        return True, "All requirements met"
    
    def start(self, location: Optional[str] = None,
              theme: Optional[str] = None,
              api_key: Optional[str] = None,
              panel_height: int = 15,
              panel_position: str = 'top',
              transparency: float = 0.85) -> bool:
        """
        Start the SoraCLI daemon.
        
        Args:
            location: Weather location (uses config if not provided)
            theme: Theme name (uses config if not provided)
            api_key: OpenWeatherMap API key
            panel_height: Height of weather panel in lines
            panel_position: 'top' or 'bottom'
            transparency: Panel transparency (0.0-1.0)
        
        Returns:
            True if daemon started successfully
        """
        # Check requirements
        ok, msg = self.check_requirements()
        if not ok:
            return False
        
        # Use config values if not provided
        location = location or self.config.location
        theme = theme or self.config.theme
        
        # Check if already running
        if self.tmux.session_exists(self.SESSION_NAME):
            return False
        
        try:
            # Create tmux session
            self.tmux.create_session(self.SESSION_NAME)
            
            # Set up split layout
            horizontal = panel_position == 'top'
            self.tmux.setup_split_layout(
                self.SESSION_NAME,
                horizontal=horizontal,
                animation_size=panel_height
            )
            
            # Start animation in pane 0
            self.tmux.start_animation(
                location=location,
                theme=theme,
                session_name=self.SESSION_NAME,
                api_key=api_key
            )
            
            # Select shell pane as active
            self._run_tmux_select_pane(1)
            
            # Write PID file
            self._write_pid_file()
            
            return True
            
        except TmuxError as e:
            # Clean up on failure
            try:
                self.stop()
            except Exception:
                pass
            return False
    
    def _run_tmux_select_pane(self, pane: int) -> None:
        """Select a pane in the session."""
        try:
            self.tmux._run_tmux([
                "select-pane", "-t", f"{self.SESSION_NAME}:0.{pane}"
            ])
        except TmuxError:
            pass  # Non-critical
    
    def stop(self) -> bool:
        """
        Stop the SoraCLI daemon.
        
        Returns:
            True if daemon was stopped
        """
        try:
            # Kill tmux session
            result = self.tmux.kill_session(self.SESSION_NAME)
            
            # Remove PID file
            self._remove_pid_file()
            
            return result
        except TmuxError as e:
            raise DaemonError(f"Failed to stop daemon: {e}")
    
    def restart(self, **kwargs) -> bool:
        """
        Restart the SoraCLI daemon.
        
        Args:
            **kwargs: Arguments passed to start()
        
        Returns:
            True if restart successful
        """
        self.stop()
        time.sleep(0.5)  # Brief pause
        return self.start(**kwargs)
    
    def get_status(self) -> dict:
        """
        Get current daemon status.
        
        Returns:
            Dictionary with status information
        """
        if not self.tmux.session_exists(self.SESSION_NAME):
            return {
                'running': False,
                'session_name': self.SESSION_NAME
            }
        
        return {
            'running': True,
            'session_name': self.SESSION_NAME,
            'location': self.config.location,
            'theme': self.config.theme,
            'start_time': 'N/A'
        }
    
    def _write_pid_file(self) -> None:
        """Write PID file for daemon tracking."""
        self.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
        self.PID_FILE.write_text(str(os.getpid()))
    
    def _remove_pid_file(self) -> None:
        """Remove PID file."""
        try:
            if self.PID_FILE.exists():
                self.PID_FILE.unlink()
        except Exception:
            pass
    
    def generate_startup_script(self, 
                                location: Optional[str] = None,
                                theme: Optional[str] = None,
                                auto_attach: bool = True) -> Path:
        """
        Generate startup script for auto-launching daemon.
        
        Args:
            location: Weather location
            theme: Theme name
            auto_attach: Whether to attach after starting
        
        Returns:
            Path to generated script
        """
        location = location or self.config.location
        theme = theme or self.config.theme
        
        # Ensure config directory exists
        self.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
        
        script_content = f'''#!/bin/bash
# SoraCLI Daemon Auto-Start Script
# Generated by SoraCLI on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
#
# Add to your shell rc file (.bashrc, .zshrc, etc.):
#   source ~/.config/soracli/startup.sh
#
# Or add this line:
#   [ -f ~/.config/soracli/startup.sh ] && source ~/.config/soracli/startup.sh

# Only run in interactive shells
[[ $- != *i* ]] && return

# Don't run if already inside tmux
[ -n "$TMUX" ] && return

# Don't run if daemon is already running
if tmux has-session -t {self.SESSION_NAME} 2>/dev/null; then
    # Daemon exists, optionally attach
    {"tmux attach-session -t " + self.SESSION_NAME if auto_attach else "# Already running, skipping attach"}
else
    # Start daemon
    python -m soracli daemon start --location "{location}" --theme {theme} {"--attach" if auto_attach else "--no-attach"}
fi
'''
        
        self.STARTUP_SCRIPT.write_text(script_content)
        self.STARTUP_SCRIPT.chmod(0o755)
        
        return self.STARTUP_SCRIPT
    
    def generate_systemd_service(self) -> Path:
        """
        Generate systemd user service file for Linux systems.
        
        Returns:
            Path to generated service file
        """
        service_dir = Path.home() / ".config" / "systemd" / "user"
        service_dir.mkdir(parents=True, exist_ok=True)
        service_file = service_dir / "soracli.service"
        
        python_path = sys.executable
        
        service_content = f'''[Unit]
Description=SoraCLI Weather Animation Daemon
After=graphical-session.target

[Service]
Type=forking
ExecStart={python_path} -m soracli daemon start --no-attach
ExecStop={python_path} -m soracli daemon stop
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target
'''
        
        service_file.write_text(service_content)
        
        return service_file
    
    def get_shell_rc_instructions(self) -> str:
        """
        Get instructions for adding auto-start to shell rc file.
        
        Returns:
            Instructions string
        """
        return f'''
To enable auto-start, add this line to your shell configuration:

For Bash (~/.bashrc):
    [ -f {self.STARTUP_SCRIPT} ] && source {self.STARTUP_SCRIPT}

For Zsh (~/.zshrc):
    [ -f {self.STARTUP_SCRIPT} ] && source {self.STARTUP_SCRIPT}

For Fish (~/.config/fish/config.fish):
    if test -f {self.STARTUP_SCRIPT}
        source {self.STARTUP_SCRIPT}
    end

Then restart your terminal or run:
    source {self.STARTUP_SCRIPT}
'''
    
    def send_to_animation_pane(self, command: str) -> bool:
        """
        Send a command to the animation pane.
        
        Args:
            command: Command to send
        
        Returns:
            True if successful
        """
        if not self.tmux.session_exists(self.SESSION_NAME):
            raise DaemonError("Daemon is not running")
        
        return self.tmux.send_command_to_pane(command, pane=0, session_name=self.SESSION_NAME)
    
    def refresh_animation(self, location: Optional[str] = None,
                          theme: Optional[str] = None) -> bool:
        """
        Refresh the animation with new settings.
        
        Args:
            location: New location
            theme: New theme
        
        Returns:
            True if successful
        """
        if not self.tmux.session_exists(self.SESSION_NAME):
            raise DaemonError("Daemon is not running")
        
        # Send Ctrl+C to stop current animation
        self.tmux._run_tmux([
            "send-keys", "-t", f"{self.SESSION_NAME}:0.0", "C-c"
        ])
        
        time.sleep(0.5)
        
        # Start new animation
        return self.tmux.start_animation(
            location=location or self.config.location,
            theme=theme or self.config.theme,
            session_name=self.SESSION_NAME
        )
