"""Provisioning module installer for the OS builder.

This module installs provisioning scripts from the pymergetic.os.provision
package into the chroot. The actual provisioning logic lives in the
separate pymergetic.os.provision package.
"""

from pathlib import Path
from typing import Optional
from pymergetic.os.builder.config import Config
from pymergetic.os.builder.utils import (
    run_command,
    mount_chroot_filesystems,
    unmount_chroot_filesystems
)
from pymergetic.os.builder.console import print_step, print_info


class ProvisionModule:
    """Provisioning module installer for the OS builder.
    
    This module installs provisioning scripts from pymergetic.os.provision
    into the chroot. The provisioning logic itself is in a separate package.
    
    Attributes:
        name: Module identifier ("provision").
        description: Human-readable description of the module.
        config: Configuration object containing OS and build settings.
    """
    
    name = "provision"
    description = "Storage provisioning and detection"
    
    def __init__(self, config: Config):
        """Initialize the provisioning module with configuration.
        
        Args:
            config: Configuration object containing OS and build settings.
        """
        self.config = config
    
    def install(self, chroot_dir: Path) -> None:
        """Install provisioning scripts and systemd service.
        
        Installs the provisioning script and systemd service from the
        pymergetic.os.provision package into the chroot.
        
        Args:
            chroot_dir: Path to the chroot directory where scripts will
                       be installed.
        """
        print_step("PROVISION", "Installing provisioning scripts...")
        
        try:
            from pymergetic.os.provision.scripts import (  # type: ignore[import-untyped]
                get_provision_script,
                get_systemd_service
            )
        except ImportError:
            print_info("pymergetic.os.provision not found, using embedded scripts")
            # Fallback to embedded scripts if package not available
            self._install_embedded_scripts(chroot_dir)
            return
        
        # Create provisioning script directory
        script_dir = chroot_dir / 'usr' / 'local' / 'bin'
        run_command(['mkdir', '-p', str(script_dir)], sudo=True)
        
        # Install provisioning script
        script_content = get_provision_script()
        self._write_script(script_dir / 'pymergetic-provision', script_content)
        
        # Install systemd service
        service_content = get_systemd_service()
        self._write_systemd_service(chroot_dir, service_content)
        
        print_info("Provisioning scripts installed")
    
    def _install_embedded_scripts(self, chroot_dir: Path) -> None:
        """Fallback: Install embedded scripts if package not available.
        
        TODO: Remove this method once pymergetic-os-provision is published to PyPI
        and can be installed as a proper dependency.
        
        Args:
            chroot_dir: Path to the chroot directory.
        """
        import tempfile
        import os
        
        # Embedded script (fallback)
        script_content = r'''#!/bin/bash
# PymergeticOS Storage Provisioning Script
# Detects ext4 volumes with fsencrypt and mounts .pymergetic storage

set -euo pipefail

LOG_FILE="/var/log/pymergetic-provision.log"
PROVISIONED_FLAG="/var/lib/pymergetic/provisioned"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

log "Starting PymergeticOS storage provisioning..."

# Function to check if filesystem has encryption enabled
has_fsencrypt() {
    local device="$1"
    local fstype
    
    fstype=$(blkid -o value -s TYPE "$device" 2>/dev/null || echo "")
    if [ "$fstype" != "ext4" ]; then
        return 1
    fi
    
    # Check if filesystem has encryption feature
    if tune2fs -l "$device" 2>/dev/null | grep -q "Filesystem features:.*encrypt"; then
        return 0
    fi
    
    return 1
}

# Function to check for .pymergetic folder using debugfs
check_pymergetic_folder() {
    local device="$1"
    
    # Use debugfs to list root directory and check for .pymergetic
    if debugfs -R "ls -p /" "$device" 2>/dev/null | grep -q "\.pymergetic"; then
        return 0
    fi
    
    return 1
}

# Function to read storage.yaml from device
read_storage_config() {
    local device="$1"
    local mountpoint
    local temp_mount
    
    temp_mount=$(mktemp -d)
    
    # Try to mount the device temporarily
    if mount -t ext4 "$device" "$temp_mount" 2>/dev/null; then
        if [ -f "$temp_mount/.pymergetic/storage.yaml" ]; then
            # Parse YAML to get mountpoint (simple grep for now)
            mountpoint=$(grep -E "^\\s*mountpoint\\s*:" "$temp_mount/.pymergetic/storage.yaml" 2>/dev/null | sed 's/.*:\\s*\\(.*\\)/\\1/' | tr -d '"' || echo "")
            umount "$temp_mount"
            rmdir "$temp_mount"
            
            if [ -n "$mountpoint" ]; then
                echo "$mountpoint"
                return 0
            fi
        fi
        umount "$temp_mount"
    fi
    
    rmdir "$temp_mount" 2>/dev/null || true
    return 1
}

# Find all block devices
log "Scanning for ext4 volumes with fsencrypt..."

provisioned=false
found_devices=()

# Get all block devices
for device in /dev/sd* /dev/nvme* /dev/vd*; do
    [ -b "$device" ] || continue
    
    # Skip if it's a partition (we want the whole device or specific partitions)
    # For now, check partitions too
    for part in "$device"*; do
        [ -b "$part" ] || continue
        
        # Check if it's mounted (skip if already mounted)
        if mountpoint -q "$part" 2>/dev/null; then
            continue
        fi
        
        # Check if it has fsencrypt
        if has_fsencrypt "$part"; then
            log "Found ext4 with fsencrypt: $part"
            
            # Check for .pymergetic folder
            if check_pymergetic_folder "$part"; then
                log "Found .pymergetic folder on $part"
                found_devices+=("$part")
                
                # Try to read storage config
                mountpoint=$(read_storage_config "$part")
                if [ -n "$mountpoint" ]; then
                    log "Found storage.yaml, mountpoint: $mountpoint"
                    
                    # Create mount point if it doesn't exist
                    mkdir -p "$mountpoint"
                    
                    # Mount the device
                    if mount -t ext4 "$part" "$mountpoint" 2>/dev/null; then
                        log "Successfully mounted $part to $mountpoint"
                        provisioned=true
                    else
                        log "Failed to mount $part to $mountpoint"
                    fi
                else
                    log "No storage.yaml found on $part"
                fi
            fi
        fi
    done
done

# If not provisioned, enter provision mode
if [ "$provisioned" = false ]; then
    log "No provisioned storage found, entering provision mode..."
    
    # Create provision mode flag
    mkdir -p "$(dirname "$PROVISIONED_FLAG")"
    touch "$PROVISIONED_FLAG.provisioning"
    
    # TODO: Implement actual provision mode
    # For now, just log that we would enter provision mode
    log "Provision mode: Mock implementation - would start provisioning wizard"
    
    # In a real implementation, this would:
    # - Start a provisioning service/script
    # - Allow user to configure storage
    # - Create .pymergetic/storage.yaml
    # - Mark as provisioned
else
    log "Storage provisioning complete"
    mkdir -p "$(dirname "$PROVISIONED_FLAG")"
    touch "$PROVISIONED_FLAG"
fi

log "Provisioning script completed"
'''
        
        service_content = '''[Unit]
Description=PymergeticOS Storage Provisioning
After=local-fs.target
Before=network.target
Wants=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/pymergetic-provision
RemainAfterExit=yes
StandardOutput=journal+console
StandardError=journal+console

[Install]
WantedBy=multi-user.target
'''
        
        script_dir = chroot_dir / 'usr' / 'local' / 'bin'
        run_command(['mkdir', '-p', str(script_dir)], sudo=True)
        self._write_script(script_dir / 'pymergetic-provision', script_content)
        self._write_systemd_service(chroot_dir, service_content)
    
    def _write_script(self, script_path: Path, content: str) -> None:
        """Write a script file to the chroot.
        
        Args:
            script_path: Path where the script will be installed.
            content: Script content.
        """
        import tempfile
        import os
        
        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.sh') as tmp:
            tmp.write(content)
            tmp_path = tmp.name
        
        try:
            run_command(['cp', tmp_path, str(script_path)], sudo=True)
            run_command(['chmod', '+x', str(script_path)], sudo=True)
        finally:
            os.unlink(tmp_path)
    
    def _write_systemd_service(self, chroot_dir: Path, content: str) -> None:
        """Write systemd service file and enable it.
        
        Args:
            chroot_dir: Path to the chroot directory.
            content: Service file content.
        """
        import tempfile
        import os
        
        service_dir = chroot_dir / 'etc' / 'systemd' / 'system'
        run_command(['mkdir', '-p', str(service_dir)], sudo=True)
        service_path = service_dir / 'pymergetic-provision.service'
        
        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.service') as tmp:
            tmp.write(content)
            tmp_path = tmp.name
        
        try:
            run_command(['cp', tmp_path, str(service_path)], sudo=True)
            
            # Enable the service in chroot
            mount_chroot_filesystems(chroot_dir)
            try:
                run_command([
                    'chroot', str(chroot_dir),
                    'systemctl', 'enable', 'pymergetic-provision.service'
                ], sudo=True, check=False)
            finally:
                unmount_chroot_filesystems(chroot_dir)
        finally:
            os.unlink(tmp_path)
    
    def get_assets(self) -> Optional[Path]:
        """Get the path to module assets directory.
        
        Returns:
            Optional[Path]: Always returns None for the provision module.
        """
        return None

