#!/usr/bin/python3
# -*- coding: utf-8 -*-

import logging
import os
import platform
import re
import socket
import subprocess
from datetime import timedelta
from pathlib import Path
from typing import Any

from sun.__metadata__ import __prgnam__

logger = logging.getLogger(__name__)


def get_static_paths() -> dict[str, Any]:
    """Returns static installation paths. Fast — no subprocess or /proc reads.

    Returns:
        dict[str, Any]: Dictionary containing installation and config paths.
    """
    return {
        'bin_path': Path('/', 'usr', 'bin'),
        'pkg_path': Path('/', 'var', 'log', 'packages'),
        'icon_path': Path('/', 'usr', 'share', 'pixmaps'),
        'desktop_path': Path('/', 'usr', 'share', 'applications'),
        'xdg_autostart': Path('/', 'etc', 'xdg', 'autostart'),
        'sun_conf_path': Path('/', 'etc', __prgnam__),
    }


def _get_gpu_info() -> str:
    """Returns GPU description string from lspci output, or empty string if unavailable."""
    vga_lines: str = ''
    try:
        result = subprocess.run(['lspci', '-mm'], stdout=subprocess.PIPE, text=True, check=False)
        vga_lines = '\n'.join(line for line in result.stdout.splitlines() if 'VGA' in line)
    except FileNotFoundError:
        logger.warning('lspci not found; GPU information unavailable')
    matches: list[str] = re.findall(r'"[^"]+"\s+"([^"]+)"\s+"([^"]+)"', vga_lines)
    return "\n     ".join(f"{m[0]}, {m[1]}" for m in matches)


def _get_cpu_cores() -> tuple[int, int]:
    """Returns (physical_cores, logical_cores) from /proc/cpuinfo and os.cpu_count()."""
    logical_cores: int = os.cpu_count() or 0
    cores: set[tuple[str, str]] = set()
    physical_id: str = '0'
    with open('/proc/cpuinfo', 'r', encoding='utf-8') as f:
        for line in f:
            if not line.strip():
                physical_id = '0'  # reset between processor entries
            elif line.startswith('physical id'):
                physical_id = line.split(':')[1].strip()
            elif line.startswith('core id'):
                cores.add((physical_id, line.split(':')[1].strip()))
    return (len(cores) if cores else logical_cores), logical_cores


def _get_mem_info() -> tuple[int, int, int, float]:
    """Returns (mem_total, mem_free, mem_used, mem_percent) from /proc/meminfo."""
    meminfo: dict[str, int] = {}
    with open('/proc/meminfo', 'r', encoding='utf-8') as f:
        for line in f:
            parts = line.split()
            if len(parts) >= 2:
                meminfo[parts[0].rstrip(':')] = int(parts[1]) * 1024
    mem_total: int = meminfo.get('MemTotal', 0)
    mem_free: int = meminfo.get('MemFree', 0)
    mem_used: int = mem_total - meminfo.get('MemAvailable', mem_free)
    mem_percent: float = round((mem_used / mem_total) * 100, 1) if mem_total else 0.0
    return mem_total, mem_free, mem_used, mem_percent


def _get_disk_info() -> tuple[int, int, int, float, str]:
    """Returns (disk_total, disk_free, disk_used, disk_percent, disk_type) from statvfs and /proc/mounts."""
    st = os.statvfs('/')
    disk_total: int = st.f_blocks * st.f_frsize
    disk_free: int = st.f_bavail * st.f_frsize
    disk_used: int = (st.f_blocks - st.f_bfree) * st.f_frsize
    disk_percent: float = round((disk_used / disk_total) * 100, 1) if disk_total else 0.0
    disk_type: str = ''
    with open('/proc/mounts', 'r', encoding='utf-8') as f:
        for line in f:
            parts = line.split()
            if len(parts) >= 3 and parts[1] == '/':
                disk_type = parts[2]
                break
    return disk_total, disk_free, disk_used, disk_percent, disk_type


def get_os_info() -> dict[str, Any]:  # pylint: disable=too-many-locals
    """Collects and returns hardware and OS information. Called only by sun info / OS Info dialog.

    Returns:
        dict[str, Any]: Dictionary containing hardware and OS information.
    """
    os_name: str = ''
    try:
        with open('/etc/os-release', 'r', encoding='utf-8') as release_file:
            for line in release_file:
                if line.startswith('PRETTY_NAME='):
                    os_name = line.split('=', 1)[1].strip().strip('"')
    except OSError:
        logger.warning('Could not read /etc/os-release')

    with open('/proc/uptime', 'r', encoding='utf-8') as f:
        uptime: str = str(timedelta(seconds=int(float(f.read().split()[0]))))

    cpu_cores, logical_cores = _get_cpu_cores()
    mem_total, mem_free, mem_used, mem_percent = _get_mem_info()
    disk_total, disk_free, disk_used, disk_percent, disk_type = _get_disk_info()

    return {
        'os_name': os_name,
        'desktop': os.getenv('XDG_CURRENT_DESKTOP'),
        'arch': platform.machine(),
        'hostname': socket.gethostname(),
        'kernel': platform.release(),
        'cpu': platform.processor(),
        'cpu_cores': cpu_cores,
        'logical_cores': logical_cores,
        'mem_used': mem_used,
        'mem_free': mem_free,
        'mem_total': mem_total,
        'mem_percent': mem_percent,
        'disk_total': disk_total,
        'disk_used': disk_used,
        'disk_free': disk_free,
        'disk_type': disk_type,
        'disk_percent': disk_percent,
        'uptime': uptime,
        'gpu': _get_gpu_info(),
    }
