import dearpygui.dearpygui as dpg
from src.core.models.models import Session, Scan, Host, Port, Service
from src.core.database.managers.scanner_manager import ScannerManager
from src.core.api.nmap import NmapScanner
from src.core.attacks.modbus_scan import ModbusScanner
from src.core.api.openvas import OpenvasScanner
from src.utils.logger import get_logger
import threading
import time
from datetime import datetime

logger = get_logger("scanner_window")

# Глобальные переменные для управления сканерами
nmap_scanner = None
modbus_scanner = None
openvas_scanner = None

def create_scanner_window(db, session: Session, parent=None):
    """Окно сканирования (с поддержкой родительского контейнера)"""
    scanner_service = ScannerManager(db)
    
    if parent:
        with dpg.child_window(
            parent=parent,
            tag="scanner_window",
            width=-1,
            height=-1
        ):
            build_scanner_content(scanner_service, session)
    else:
        with dpg.child_window(
            tag="scanner_window",
            width=-1,
            height=-1
        ):
            build_scanner_content(scanner_service, session)

def build_scanner_content(scanner_service, session):
    """Построение содержимого окна сканирования"""
    dpg.add_text("Сканирование", color=(255, 255, 255))
    dpg.add_separator()
    dpg.add_spacer(height=10)
    
    with dpg.tab_bar(tag="scan_tabs"):
        with dpg.tab(tag="nmap_tab", label="Nmap Scanning"):
            create_nmap_tab(scanner_service, session)
        
        with dpg.tab(tag="openvas_tab", label="OpenVAS Scanning"):
            create_openvas_tab(scanner_service, session)
        
        with dpg.tab(tag="modbus_tab", label="Modbus Scanning"):
            create_modbus_tab(scanner_service, session)
        
        with dpg.tab(tag="results_tab", label="Scan Results"):
            create_results_tab(scanner_service, session)

def create_nmap_tab(scanner_service, session):
    """Вкладка Nmap сканирования"""
    with dpg.group():
        with dpg.group(tag="nmap_config_group"):
            dpg.add_text("Конфигурация сканирования")
            dpg.add_text("Цель:")
            target_input = dpg.add_input_text(tag="nmap_target", width=300)
            dpg.add_text("Тип сканирования:")
            scan_type = dpg.add_combo(
                tag="nmap_scan_type",
                items=["Quick Scan", "Intensive Scan", "Full Scan", "Custom Scan"],
                default_value="Quick Scan",
                width=200
            )
            dpg.add_text("Пользовательские аргументы:")
            custom_args = dpg.add_input_text(tag="nmap_custom_args", width=300)
        
        dpg.add_button(
            label="Начать сканирование Nmap",
            callback=lambda: start_nmap_scan(
                scanner_service, 
                session,
                dpg.get_value(target_input),
                dpg.get_value(scan_type),
                dpg.get_value(custom_args)
            ),
            width=200,
            height=40
        )
        dpg.add_spacer(height=10)
        
        dpg.add_button(
            label="Остановить сканирование",
            callback=lambda: stop_nmap_scan(),
            width=200,
            height=40
        )
        dpg.add_spacer(height=10)
        
        dpg.add_text("Вывод:")
        dpg.add_input_text(
            tag="nmap_output",
            multiline=True,
            height=300,
            width=-1,
            readonly=True
        )

def start_nmap_scan(scanner_service, session, target, scan_type, custom_args):
    """Запуск Nmap сканирования"""
    global nmap_scanner
    
    if not target:
        logger.warning("Nmap scan started without target")
        dpg.set_value("nmap_output", "Ошибка: Не указана цель сканирования\n")
        return
    
    dpg.set_value("nmap_output", f"🚀 Начало сканирования {scan_type} на {target}...\n")
    
    scan = Scan(
        session_id=session.id,
        tool="nmap",
        args=f"Тип: {scan_type}, Аргументы: {custom_args}",
        summary="В процессе",
        created_at=datetime.utcnow()
    )
    
    saved_scan = scanner_service.save_scan(scan)
    if saved_scan:
        dpg.set_value("nmap_output", dpg.get_value("nmap_output") + f"📝 ID сканирования: {saved_scan.id}\n")
    
    nmap_scanner = NmapScanner(
        ip=target,
        scan_type=scan_type,
        custom_args=custom_args
    )
    
    thread = threading.Thread(
        target=run_nmap_scan,
        args=(scanner_service, session, saved_scan.id, nmap_scanner)
    )
    thread.start()

def stop_nmap_scan():
    """Остановка Nmap сканирования"""
    global nmap_scanner
    if nmap_scanner:
        nmap_scanner.stop()
        dpg.set_value("nmap_output", dpg.get_value("nmap_output") + "🛑 Сканирование остановлено пользователем\n")
        logger.info("Nmap scan stopped by user")

def run_nmap_scan(scanner_service, session, scan_id, scanner):
    """Выполнение Nmap сканирования (в потоке)"""
    try:
        dpg.set_value("nmap_output", dpg.get_value("nmap_output") + "🔍 Сканирование сети...\n")
        
        result = scanner.start_scan()
        
        if 'error' in result:
            dpg.set_value("nmap_output", dpg.get_value("nmap_output") + f"❌ Ошибка: {result['error']}\n")
            scan = Scan(
                id=scan_id,
                summary=f"Ошибка: {result['error']}",
                duration=result.get('duration', 0),
                created_at=datetime.utcnow()
            )
            scanner_service.update_scan(scan)
            return
        
        for ip, host_data in result.get("hosts", {}).items():
            os_name = "Неизвестно"
            if host_data.get("osmatch"):
                os_name = host_data["osmatch"][0].get("name", "Неизвестно")
            
            host_obj = Host(
                scan_id=scan_id,
                ip=ip,
                mac=host_data.get("macaddress", {}).get("addr", "N/A"),
                os=os_name
            )
            saved_host = scanner_service.save_host(scan_id, host_obj)
            
            output = dpg.get_value("nmap_output") + f"🔍 Найден хост: {ip} ({os_name})\n"
            output += f"MAC: {host_obj.mac}\n"
            dpg.set_value("nmap_output", output)
            
            for port_info in host_data.get("ports", []):
                port_id = port_info.get("portid", "N/A")
                protocol = port_info.get("protocol", "N/A")
                state = port_info.get("state", "unknown")
                service = port_info.get("service", {})
                
                port_obj = Port(
                    host_id=saved_host.id,
                    protocol=protocol,
                    port_num=int(port_id) if port_id.isdigit() else None,
                    state=state
                )
                saved_port = scanner_service.save_port(saved_host.id, port_obj)
                
                service_obj = Service(
                    port_id=saved_port.id,
                    name=service.get("name", "Unknown"),
                    product=service.get("product", ""),
                    version=service.get("version", ""),
                    extrainfo=service.get("extrainfo", "")
                )
                scanner_service.save_service(saved_port.id, service_obj)
                
                output = dpg.get_value("nmap_output") 
                output += f"    Порт: {port_id}/{protocol} - "
                output += f"{service_obj.name} {service_obj.product} {service_obj.version}\n"
                dpg.set_value("nmap_output", output)
        
        scan = Scan(
            id=scan_id,
            summary=f"Найдено {result.get('hosts_up', 0)} хостов",
            duration=result.get('duration', 0),
            created_at=datetime.utcnow()
        )
        scanner_service.update_scan(scan)
        
        output = dpg.get_value("nmap_output") 
        output += f"✅ Сканирование завершено за {result.get('duration', 0):.2f} секунд\n"
        output += f"Найдено хостов: {result.get('hosts_up', 0)}\n"
        dpg.set_value("nmap_output", output)
        
        if dpg.does_item_exist("scan_list"):
            load_scan_history(scanner_service, session, "scan_list")
            
    except Exception as e:
        output = dpg.get_value("nmap_output") + f"❌ Критическая ошибка: {str(e)}\n"
        dpg.set_value("nmap_output", output)
        logger.error(f"Nmap scan failed: {e}")
        
        scan = Scan(
            id=scan_id,
            summary=f"Ошибка: {str(e)}",
            duration=time.time() - scanner.start_time if hasattr(scanner, 'start_time') else 0,
            created_at=datetime.utcnow()
        )
        scanner_service.update_scan(scan)

def create_openvas_tab(scanner_service, session):
    """Вкладка OpenVAS сканирования"""
    with dpg.group():
        # Группа для настроек подключения
        with dpg.group(tag="openvas_connection_group"):
            dpg.add_text("Настройки подключения к OpenVAS")
            dpg.add_text("Сокет (например, /var/run/gvmd.sock):")
            socket_input = dpg.add_input_text(tag="openvas_socket", default_value="/var/run/gvmd.sock", width=300)
            dpg.add_text("Имя пользователя:")
            username_input = dpg.add_input_text(tag="openvas_username", width=300)
            dpg.add_text("Пароль:")
            password_input = dpg.add_input_text(tag="openvas_password", password=True, width=300)
            dpg.add_button(
                label="Подключиться",
                callback=lambda: connect_to_openvas(
                    dpg.get_value(socket_input),
                    dpg.get_value(username_input),
                    dpg.get_value(password_input)
                ),
                width=200,
                height=40
            )
            dpg.add_spacer(height=10)
        
        # Группа для настроек сканирования (скрыта до подключения)
        with dpg.group(tag="openvas_scan_group", show=False):
            dpg.add_text("Настройки сканирования")
            dpg.add_text("Имя сканирования:")
            scan_name_input = dpg.add_input_text(tag="openvas_scan_name", width=300)
            dpg.add_text("Цели (IP-адреса или сети, через запятую):")
            targets_input = dpg.add_input_text(tag="openvas_targets", width=300)
            dpg.add_text("Конфигурация сканирования:")
            config_combo = dpg.add_combo(tag="openvas_config", items=[], width=300)
            dpg.add_button(
                label="Начать сканирование",
                callback=lambda: start_openvas_scan(
                    scanner_service,
                    session,
                    dpg.get_value(scan_name_input),
                    dpg.get_value(targets_input),
                    dpg.get_value(config_combo)
                ),
                width=200,
                height=40
            )
            dpg.add_spacer(height=10)
        
        # Область вывода
        dpg.add_text("Вывод:")
        dpg.add_input_text(
            tag="openvas_output",
            multiline=True,
            height=300,
            width=-1,
            readonly=True
        )

def connect_to_openvas(socket_path, username, password):
    """Подключение к OpenVAS"""
    global openvas_scanner
    try:
        openvas_scanner = OpenvasScanner(socket_path=socket_path)
        openvas_scanner.connect(username, password)
        configs = openvas_scanner.get_configurations()
        dpg.configure_item("openvas_config", items=configs)
        dpg.set_value("openvas_output", dpg.get_value("openvas_output") + "✅ Подключено к OpenVAS\n")
        dpg.configure_item("openvas_scan_group", show=True)
    except Exception as e:
        dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"❌ Ошибка подключения: {str(e)}\n")
        logger.error(f"OpenVAS connection failed: {e}")

def start_openvas_scan(scanner_service, session, scan_name, targets, config_name):
    """Запуск OpenVAS сканирования"""
    global openvas_scanner
    if openvas_scanner is None:
        dpg.set_value("openvas_output", dpg.get_value("openvas_output") + "❌ Не подключено к OpenVAS\n")
        return
    
    try:
        # Создание цели
        target_id = openvas_scanner.create_target(scan_name, targets.split(','))
        # Создание задачи
        task_id = openvas_scanner.create_task(scan_name, config_name, target_id)
        # Запуск задачи
        openvas_scanner.start_task(task_id)
        dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"🚀 Задача {task_id} запущена\n")
        
        # Сохранение сканирования в базе данных
        scan = Scan(
            session_id=session.id,
            tool="openvas",
            args=f"Имя: {scan_name}, Цели: {targets}, Конфигурация: {config_name}",
            summary="В процессе",
            created_at=datetime.utcnow()
        )
        saved_scan = scanner_service.save_scan(scan)
        if saved_scan:
            dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"📝 ID сканирования: {saved_scan.id}\n")
        
        # Запуск потока для отслеживания статуса задачи
        thread = threading.Thread(
            target=monitor_openvas_task,
            args=(scanner_service, session, saved_scan.id, task_id)
        )
        thread.start()
        
    except Exception as e:
        dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"❌ Ошибка: {str(e)}\n")
        logger.error(f"OpenVAS scan failed: {e}")

def monitor_openvas_task(scanner_service, session, scan_id, task_id):
    """Отслеживание статуса задачи OpenVAS"""
    global openvas_scanner
    try:
        start_time = time.time()
        while True:
            status = openvas_scanner.get_task_status(task_id)
            if status == 'Done':
                report = openvas_scanner.get_report(task_id)
                if report:
                    dpg.set_value("openvas_output", dpg.get_value("openvas_output") + "✅ Сканирование завершено\n")
                    dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"Отчет:\n{report}\n")
                else:
                    dpg.set_value("openvas_output", dpg.get_value("openvas_output") + "❌ Отчет не найден\n")
                break
            elif status in ['Running', 'Requested']:
                dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"⏳ Статус: {status}\n")
            else:
                dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"❌ Неизвестный статус: {status}\n")
                break
            time.sleep(10)
        
        # Обновление статуса сканирования в базе данных
        scan = Scan(
            id=scan_id,
            summary="OpenVAS сканирование завершено",
            duration=int(time.time() - start_time),
            created_at=datetime.utcnow()
        )
        scanner_service.update_scan(scan)
        
        if dpg.does_item_exist("scan_list"):
            load_scan_history(scanner_service, session, "scan_list")
            
    except Exception as e:
        dpg.set_value("openvas_output", dpg.get_value("openvas_output") + f"❌ Ошибка: {str(e)}\n")
        logger.error(f"OpenVAS task monitoring failed: {e}")

def create_modbus_tab(scanner_service, session):
    """Вкладка Modbus сканирования"""
    with dpg.group():
        with dpg.group(tag="modbus_config_group"):
            dpg.add_text("Конфигурация Modbus сканирования")
            dpg.add_text("IP-адрес:")
            ip_input = dpg.add_input_text(tag="modbus_ip", width=300)
            dpg.add_text("Порт:")
            port_input = dpg.add_input_int(tag="modbus_port", default_value=502, width=150)
            dpg.add_text("Coils (начало - конец):")
            with dpg.group(horizontal=True):
                coil_start = dpg.add_input_int(tag="modbus_coil_start", default_value=0, width=150)
                coil_end = dpg.add_input_int(tag="modbus_coil_end", default_value=100, width=150)
            dpg.add_text("Discrete Inputs (начало - конец):")
            with dpg.group(horizontal=True):
                discrete_start = dpg.add_input_int(tag="modbus_discrete_start", default_value=0, width=150)
                discrete_end = dpg.add_input_int(tag="modbus_discrete_end", default_value=100, width=150)
            dpg.add_text("Holding Registers (начало - конец):")
            with dpg.group(horizontal=True):
                holding_start = dpg.add_input_int(tag="modbus_holding_start", default_value=0, width=150)
                holding_end = dpg.add_input_int(tag="modbus_holding_end", default_value=100, width=150)
            dpg.add_text("Input Registers (начало - конец):")
            with dpg.group(horizontal=True):
                input_start = dpg.add_input_int(tag="modbus_input_start", default_value=0, width=150)
                input_end = dpg.add_input_int(tag="modbus_input_end", default_value=100, width=150)
            dpg.add_text("Длительность сканирования (сек):")
            duration_input = dpg.add_input_int(tag="modbus_duration", default_value=10, width=150)
            dpg.add_text("Размер блока:")
            block_size_input = dpg.add_input_int(tag="modbus_block_size", default_value=50, width=150)
        
        dpg.add_button(
            label="Начать Modbus сканирование",
            callback=lambda: start_modbus_scan(
                scanner_service,
                session,
                dpg.get_value(ip_input),
                dpg.get_value(port_input),
                (dpg.get_value(coil_start), dpg.get_value(coil_end)),
                (dpg.get_value(discrete_start), dpg.get_value(discrete_end)),
                (dpg.get_value(holding_start), dpg.get_value(holding_end)),
                (dpg.get_value(input_start), dpg.get_value(input_end)),
                dpg.get_value(duration_input),
                dpg.get_value(block_size_input)
            ),
            width=200,
            height=40
        )
        dpg.add_spacer(height=10)
        
        dpg.add_text("Вывод:")
        dpg.add_input_text(
            tag="modbus_output",
            multiline=True,
            height=300,
            width=-1,
            readonly=True
        )

def start_modbus_scan(scanner_service, session, ip, port, coil_range, discrete_range, holding_range, input_range, duration, block_size):
    """Запуск Modbus сканирования"""
    global modbus_scanner
    
    if not ip:
        logger.warning("Modbus scan started without IP")
        dpg.set_value("modbus_output", "Ошибка: Не указан IP-адрес\n")
        return
    
    try:
        if not (0 <= port <= 65535):
            raise ValueError("Порт должен быть в диапазоне 0-65535")
        if not (coil_range[0] <= coil_range[1] and discrete_range[0] <= discrete_range[1] and
                holding_range[0] <= holding_range[1] and input_range[0] <= input_range[1]):
            raise ValueError("Начало диапазона должно быть меньше или равно концу")
        if duration <= 0:
            raise ValueError("Длительность сканирования должна быть положительной")
        if block_size <= 0:
            raise ValueError("Размер блока должен быть положительным")
    except ValueError as e:
        logger.warning(f"Invalid Modbus scan parameters: {e}")
        dpg.set_value("modbus_output", f"Ошибка: {str(e)}\n")
        return
    
    dpg.set_value("modbus_output", f"🚀 Начало Modbus сканирования на {ip}:{port}...\n")
    
    scan = Scan(
        session_id=session.id,
        tool="modbus",
        args=f"IP: {ip}, Port: {port}, Coils: {coil_range}, Discrete: {discrete_range}, Holding: {holding_range}, Input: {input_range}, Duration: {duration}s, Block: {block_size}",
        summary="В процессе",
        created_at=datetime.utcnow()
    )
    
    saved_scan = scanner_service.save_scan(scan)
    if saved_scan:
        dpg.set_value("modbus_output", dpg.get_value("modbus_output") + f"📝 ID сканирования: {saved_scan.id}\n")
    
    modbus_scanner = ModbusScanner(
        host=ip,
        port=port,
        coil_range=coil_range,
        discrete_input_range=discrete_range,
        holding_register_range=holding_range,
        input_register_range=input_range,
        scan_duration=duration,
        block_size=block_size
    )
    
    thread = threading.Thread(
        target=run_modbus_scan,
        args=(scanner_service, session, saved_scan.id, modbus_scanner)
    )
    thread.start()

def run_modbus_scan(scanner_service, session, scan_id, scanner):
    """Выполнение Modbus сканирования (в потоке)"""
    try:
        dpg.set_value("modbus_output", dpg.get_value("modbus_output") + "🔍 Подключение к устройству...\n")
        
        start_time = time.time()
        results = scanner.scan_registers()
        duration = int(time.time() - start_time)
        
        if results is None:
            output = dpg.get_value("modbus_output") + "❌ Ошибка: Не удалось выполнить сканирование, проверьте подключение устройства\n"
            dpg.set_value("modbus_output", output)
            scan = Scan(
                id=scan_id,
                summary="Ошибка: Сканирование не выполнено",
                duration=duration,
                created_at=datetime.utcnow()
            )
            scanner_service.update_scan(scan)
            return
        
        # Convert results to strings of active addresses
        active_coils = ",".join(str(addr) for addr in sorted(results.active_coils.keys())) if results.active_coils else ""
        active_discrete = ",".join(str(addr) for addr in sorted(results.active_discrete_inputs.keys())) if results.active_discrete_inputs else ""
        active_holding = ",".join(str(addr) for addr in sorted(results.active_holding_registers.keys())) if results.active_holding_registers else ""
        active_input = ",".join(str(addr) for addr in sorted(results.active_input_registers.keys())) if results.active_input_registers else ""
        
        # Save results to database
        modbus_results = {
            "active_coils": active_coils,
            "active_discrete_inputs": active_discrete,
            "active_holding_registers": active_holding,
            "active_input_registers": active_input
        }
        scanner_service.save_modbus_result(scan_id, modbus_results)
        
        # Update scan status
        scan = Scan(
            id=scan_id,
            summary=f"Modbus сканирование завершено: {len(results.active_coils)} coils, {len(results.active_discrete_inputs)} discrete inputs, {len(results.active_holding_registers)} holding registers, {len(results.active_input_registers)} input registers",
            duration=duration,
            created_at=datetime.utcnow()
        )
        scanner_service.update_scan(scan)
        
        # Display results
        output = dpg.get_value("modbus_output") + f"✅ Сканирование завершено за {duration:.2f} секунд!\n"
        output += f"Активные Coils: {active_coils or 'Нет'}\n"
        output += f"Активные Discrete Inputs: {active_discrete or 'Нет'}\n"
        output += f"Активные Holding Registers: {active_holding or 'Нет'}\n"
        output += f"Активные Input Registers: {active_input or 'Нет'}\n"
        dpg.set_value("modbus_output", output)
        
        # Update scan history
        if dpg.does_item_exist("scan_list"):
            load_scan_history(scanner_service, session, "scan_list")
            
    except Exception as e:
        output = dpg.get_value("modbus_output") + f"❌ Ошибка: {str(e)}\n"
        dpg.set_value("modbus_output", output)
        logger.error(f"Modbus scan failed: {e}")
        
        scan = Scan(
            id=scan_id,
            summary=f"Ошибка: {str(e)}",
            duration=int(time.time() - start_time) if 'start_time' in locals() else 0,
            created_at=datetime.utcnow()
        )
        scanner_service.update_scan(scan)

def create_results_tab(scanner_service, session):
    """Вкладка результатов сканирования"""
    with dpg.group():
        dpg.add_text("История сканирований:")
        scan_list = dpg.add_listbox(
            tag="scan_list",
            width=-1,
            num_items=10,
            callback=lambda s: show_scan_details(scanner_service, session, dpg.get_value(s))
        )
        
        load_scan_history(scanner_service, session, "scan_list")
        dpg.add_spacer(height=10)
        
        dpg.add_text("Детали сканирования:")
        dpg.add_input_text(
            tag="scan_details",
            multiline=True,
            height=300,
            width=-1,
            readonly=True
        )

def load_scan_history(scanner_service, session, scan_list):
    """Загрузка истории сканирований"""
    scans = scanner_service.get_scans_by_session(session.id)
    scan_items = []
    
    for scan in scans:
        created_at = scan.created_at
        if isinstance(created_at, str):
            try:
                created_at = datetime.fromisoformat(created_at.replace('Z', '+00:00'))
            except ValueError:
                logger.warning(f"Invalid created_at format for scan {scan.id}: {created_at}")
                created_at = datetime.utcnow()
        
        item = f"ID:{scan.id} - {scan.tool} scan - {created_at.strftime('%Y-%m-%d %H:%M')}"
        if scan.summary:
            item += f" ({scan.summary})"
        scan_items.append(item)
    
    dpg.configure_item(scan_list, items=scan_items)

def show_scan_details(scanner_service, session, scan_index):
    """Отображение деталей сканирования"""
    if scan_index is None:
        return
    
    scans = scanner_service.get_scans_by_session(session.id)
    try:
        # Extract scan ID from "ID:{id} - tool scan - ..."
        scan_id = int(scan_index.split()[0].split(':')[1])
        # Find scan by ID
        scan = next((s for s in scans if s.id == scan_id), None)
        if scan is None:
            logger.warning(f"Scan with ID {scan_id} not found")
            return
    except (ValueError, IndexError):
        logger.warning(f"Failed to parse scan index: {scan_index}")
        return
    
    created_at = scan.created_at
    if isinstance(created_at, str):
        try:
            created_at = datetime.fromisoformat(created_at.replace('Z', '+00:00'))
        except ValueError:
            logger.warning(f"Invalid created_at format for scan {scan.id}: {created_at}")
            created_at = datetime.utcnow()
    
    details = f"Scan ID: {scan.id}\n"
    details += f"Tool: {scan.tool}\n"
    details += f"Args: {scan.args}\n"
    details += f"Summary: {scan.summary}\n"
    details += f"Duration: {scan.duration} seconds\n"
    details += f"Created: {created_at.strftime('%Y-%m-%d %H:%M')}\n"
    
    if scan.tool == "nmap":
        hosts = scanner_service.get_hosts_by_scan(scan.id)
        if hosts:
            details += "\nHosts:\n"
            for host in hosts:
                details += f"  IP: {host.ip}, MAC: {host.mac}, OS: {host.os}\n"
                ports = scanner_service.get_ports_by_host(host.id)
                if ports:
                    details += "  Ports:\n"
                    for port in ports:
                        details += f"    {port.port_num}/{port.protocol} ({port.state})\n"
                        services = scanner_service.get_services_by_port(port.id)
                        if services:
                            for service in services:
                                details += f"      Service: {service.name} {service.product} {service.version} ({service.extrainfo})\n"
    elif scan.tool == "modbus":
        modbus_result = scanner_service.get_modbus_result(scan.id)
        if modbus_result:
            details += "\nModbus Results:\n"
            details += f"  Active Coils: {modbus_result.active_coils or 'Нет'}\n"
            details += f"  Active Discrete Inputs: {modbus_result.active_discrete_inputs or 'Нет'}\n"
            details += f"  Active Holding Registers: {modbus_result.active_holding_registers or 'Нет'}\n"
            details += f"  Active Input Registers: {modbus_result.active_input_registers or 'Нет'}\n"
    
    dpg.set_value("scan_details", details)