import psutil         # Библиотека для получения информации о процессах и системе
import platform       # Для получения информации о системе (ОС, архитектура и т.д.)
import wmi            # Для работы с Windows Management Instrumentation — получения подробной информации о железе
import ctypes         # Для вызова функций Windows API (здесь — получение разрешения экрана)
from datetime import datetime  # Для работы с датой и временем (имя файла отчёта)

# Класс Logger — отвечает за вывод информации в консоль и запись в файл одновременно
class Logger:
    def __init__(self, filename):
        # Открываем файл для записи с кодировкой utf-8
        self.file = open(filename, 'w', encoding='utf-8')

    def write(self, text):
        # Выводим строку в консоль
        print(text)
        # Записываем строку в файл с добавлением символа переноса строки
        self.file.write(text + '\n')

    def close(self):
        # Закрываем файл
        self.file.close()

# Функция получения и вывода информации о процессоре
def get_cpu_info(log):
    c = wmi.WMI()  # Создаём объект для работы с WMI
    for cpu in c.Win32_Processor():
        log.write(f"Процессор: {cpu.Name}")  # Модель процессора
        log.write(f"Архитектура: {cpu.Architecture}")  # Архитектура: 0 = x86, 9 = x64 и др.
        log.write(f"Количество ядер: {cpu.NumberOfCores}")  # Физические ядра
        log.write(f"Количество потоков: {cpu.NumberOfLogicalProcessors}")  # Логические процессоры (потоки)
        log.write(f"Максимальная тактовая частота: {cpu.MaxClockSpeed} МГц")  # Частота в мегагерцах
        log.write(f"Кэш L2: {cpu.L2CacheSize} КБ")  # Кэш второго уровня
        log.write(f"Кэш L3: {cpu.L3CacheSize} КБ")  # Кэш третьего уровня
        log.write(f"Статус: {cpu.Status}")  # Статус устройства (например, OK)
        log.write(f"Производитель: {cpu.Manufacturer}")  # Производитель процессора
        log.write("-" * 40)  # Разделитель для удобства чтения

# Функция получения и вывода информации об оперативной памяти
def get_ram_info(log):
    c = wmi.WMI()
    log.write("Модули оперативной памяти:")
    for mem in c.Win32_PhysicalMemory():
        log.write(f"  Производитель: {mem.Manufacturer}")  # Производитель модуля
        log.write(f"  Модель: {mem.PartNumber}")  # Модель / номер детали
        log.write(f"  Объем: {round(int(mem.Capacity) / (1024**3), 2)} ГБ")  # Размер модуля в ГБ
        log.write(f"  Тип памяти: {mem.MemoryType}")  # Тип (числовой код, например DDR3, DDR4)
        log.write(f"  Скорость: {mem.Speed} МГц")  # Частота памяти
        log.write(f"  Серийный номер: {mem.SerialNumber}")  # Серийник модуля
        log.write("-" * 20)
    total_mem = psutil.virtual_memory().total  # Общий объём ОЗУ (оперативной памяти)
    log.write(f"Общий объем ОЗУ: {round(total_mem / (1024 ** 3), 2)} ГБ")
    log.write("-" * 40)

# Функция получения и вывода информации о накопителях (жесткие диски, SSD)
def get_storage_info(log):
    c = wmi.WMI()
    log.write("Накопители данных:")
    for disk in c.Win32_DiskDrive():
        log.write(f"  Модель: {disk.Model}")  # Модель диска
        log.write(f"  Интерфейс: {disk.InterfaceType}")  # Тип подключения (SATA, USB и др.)
        log.write(f"  Объем: {round(int(disk.Size) / (1024**3), 2)} ГБ")  # Размер в ГБ
        log.write(f"  Серийный номер: {disk.SerialNumber}")  # Серийный номер диска
        log.write(f"  Статус: {disk.Status}")  # Статус устройства (например, OK)
        log.write("-" * 20)
    log.write("-" * 40)

# Функция получения и вывода информации о видеокарте
def get_gpu_info(log):
    c = wmi.WMI()
    for gpu in c.Win32_VideoController():
        log.write(f"Видеокарта: {gpu.Name}")  # Название видеокарты
        log.write(f"Производитель: {gpu.AdapterCompatibility}")  # Производитель (NVIDIA, AMD и др.)
        log.write(f"Объем видеопамяти: {round(int(gpu.AdapterRAM) / (1024 ** 3), 2)} ГБ")  # Объем памяти
        log.write(f"Версия драйвера: {gpu.DriverVersion}")  # Версия установленного драйвера
        log.write(f"Статус: {gpu.Status}")  # Статус устройства
        log.write("-" * 40)

# Функция для получения разрешения экрана с помощью Windows API
def get_display_info(log):
    user32 = ctypes.windll.user32
    user32.SetProcessDPIAware()  # Делает процесс DPI-aware, чтобы получить реальное разрешение экрана
    width = user32.GetSystemMetrics(0)  # Ширина экрана
    height = user32.GetSystemMetrics(1)  # Высота экрана
    log.write(f"Разрешение экрана: {width} x {height}")
    log.write("-" * 40)

# Функция получения и вывода списка подключённых устройств Plug and Play
def get_connected_devices(log):
    c = wmi.WMI()
    log.write("Подключённые устройства (Plug and Play):")
    devices = c.Win32_PnPEntity()  # Получаем все устройства Plug and Play
    for device in devices:
        if device.Name:  # Выводим только устройства с именем
            log.write(f"  Устройство: {device.Name}")  # Имя устройства
            if hasattr(device, 'Manufacturer'):
                log.write(f"    Производитель: {device.Manufacturer}")  # Производитель, если есть
            if hasattr(device, 'Status'):
                log.write(f"    Статус: {device.Status}")  # Статус устройства
            log.write("-" * 20)
    log.write("-" * 40)

# Главная функция — точка входа программы
def main():
    # Формируем имя файла отчёта с текущей датой и временем
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"system_report_{timestamp}.txt"
    log = Logger(filename)  # Создаём объект Logger для записи отчёта

    # Выводим общую информацию о системе
    log.write(f"Информация о системе: {platform.system()} {platform.release()} ({platform.version()})")
    log.write(f"Архитектура системы: {platform.machine()}")
    log.write("-" * 40)

    # Вызываем функции для сбора и вывода информации
    get_cpu_info(log)
    get_ram_info(log)
    get_storage_info(log)
    get_gpu_info(log)
    get_display_info(log)
    get_connected_devices(log)

    log.close()  # Закрываем файл с отчётом
    print(f"Отчёт сохранён в файл: {filename}")  # Сообщаем пользователю имя файла отчёта

# Запускаем главную функцию, если скрипт выполнен напрямую
if __name__ == "__main__":
    main()
