"""Diagnóstico do sistema e download de modelos."""

from __future__ import annotations

import os
import platform
import shutil
import sys
from dataclasses import dataclass

os.environ["PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK"] = "True"


@dataclass
class CheckResult:
    """Resultado de uma verificação."""

    name: str
    ok: bool
    detail: str
    required: bool = True


def check_python() -> CheckResult:
    """Verifica versão do Python."""
    ver = sys.version_info
    ok = ver >= (3, 10)
    return CheckResult(
        name="Python",
        ok=ok,
        detail=f"{ver.major}.{ver.minor}.{ver.micro}" + ("" if ok else " (requer >= 3.10)"),
    )


def check_platform() -> CheckResult:
    """Info do sistema operacional."""
    info = f"{platform.system()} {platform.machine()}"
    return CheckResult(name="Sistema", ok=True, detail=info)


def check_paddle() -> CheckResult:
    """Verifica se PaddlePaddle está instalado."""
    try:
        import paddle

        return CheckResult(name="PaddlePaddle", ok=True, detail=f"v{paddle.__version__}")
    except ImportError:
        return CheckResult(
            name="PaddlePaddle",
            ok=False,
            detail="NÃO instalado — instale paddlepaddle ou paddlepaddle-gpu",
        )


def check_cuda() -> CheckResult:
    """Verifica suporte CUDA."""
    try:
        import paddle

        has_cuda = paddle.device.is_compiled_with_cuda()
        if has_cuda:
            count = paddle.device.cuda.device_count()
            if count > 0:
                # Pega nome da GPU
                try:
                    props = paddle.device.cuda.get_device_properties(0)
                    gpu_name = props.name
                except Exception:
                    gpu_name = "desconhecida"
                return CheckResult(
                    name="GPU CUDA",
                    ok=True,
                    detail=f"{count} GPU(s) — {gpu_name}",
                )
            return CheckResult(
                name="GPU CUDA",
                ok=False,
                detail="CUDA compilado mas nenhuma GPU encontrada",
                required=False,
            )
        return CheckResult(
            name="GPU CUDA",
            ok=False,
            detail="PaddlePaddle compilado sem CUDA (versão CPU)",
            required=False,
        )
    except ImportError:
        return CheckResult(
            name="GPU CUDA", ok=False, detail="PaddlePaddle não instalado", required=False
        )


def check_paddleocr() -> CheckResult:
    """Verifica se PaddleOCR está instalado."""
    try:
        import paddleocr

        ver = getattr(paddleocr, "__version__", "desconhecida")
        return CheckResult(name="PaddleOCR", ok=True, detail=f"v{ver}")
    except ImportError:
        return CheckResult(
            name="PaddleOCR",
            ok=False,
            detail="NÃO instalado — instale paddleocr[all]",
        )


def check_pypdfium2() -> CheckResult:
    """Verifica se pypdfium2 está instalado."""
    try:
        import pypdfium2

        ver = getattr(pypdfium2, "__version__", getattr(pypdfium2, "V_PYPDFIUM2", "?"))
        return CheckResult(name="pypdfium2", ok=True, detail=f"v{ver}")
    except ImportError:
        return CheckResult(
            name="pypdfium2", ok=False, detail="NÃO instalado — instale pypdfium2"
        )


def check_disk_space() -> CheckResult:
    """Verifica espaço em disco disponível."""
    home = os.path.expanduser("~")
    usage = shutil.disk_usage(home)
    free_gb = usage.free / (1024**3)
    ok = free_gb >= 2.0
    return CheckResult(
        name="Espaço em disco",
        ok=ok,
        detail=f"{free_gb:.1f} GB livres" + ("" if ok else " (recomendado >= 2 GB)"),
    )


def check_ram() -> CheckResult:
    """Verifica RAM disponível."""
    try:
        import psutil

        mem = psutil.virtual_memory()
        total_gb = mem.total / (1024**3)
        ok = total_gb >= 4.0
        return CheckResult(
            name="RAM",
            ok=ok,
            detail=f"{total_gb:.1f} GB total" + ("" if ok else " (recomendado >= 4 GB)"),
        )
    except ImportError:
        # Fallback: ler /proc/meminfo no Linux
        try:
            with open("/proc/meminfo") as f:
                for line in f:
                    if line.startswith("MemTotal:"):
                        kb = int(line.split()[1])
                        total_gb = kb / (1024**2)
                        ok = total_gb >= 4.0
                        return CheckResult(
                            name="RAM",
                            ok=ok,
                            detail=f"{total_gb:.1f} GB total"
                            + ("" if ok else " (recomendado >= 4 GB)"),
                        )
        except Exception:
            pass
        return CheckResult(name="RAM", ok=True, detail="não foi possível verificar")


def _model_cached(model_name: str) -> bool:
    """Verifica se um modelo já está em cache local."""
    cache_dir = os.path.expanduser(f"~/.paddlex/official_models/{model_name}")
    return os.path.isdir(cache_dir)


def check_models() -> list[CheckResult]:
    """Verifica quais modelos OCR estão em cache."""
    models = [
        "PP-OCRv5_mobile_det",
        "PP-OCRv5_mobile_rec",
        "PP-OCRv5_server_det",
        "PP-OCRv5_server_rec",
    ]
    results = []
    for m in models:
        cached = _model_cached(m)
        results.append(
            CheckResult(
                name=f"Modelo {m}",
                ok=cached,
                detail="em cache" if cached else "não baixado",
                required=False,
            )
        )
    return results


def download_models(models: list[str] | None = None, device: str = "cpu") -> list[str]:
    """Baixa modelos criando uma instância PaddleOCR temporária.

    Returns:
        Lista de modelos baixados com sucesso.
    """
    from paddleocr import PaddleOCR

    if models is None:
        models = ["mobile", "server"]

    downloaded = []
    for model_type in models:
        try:
            PaddleOCR(
                text_detection_model_name=f"PP-OCRv5_{model_type}_det",
                text_recognition_model_name=f"PP-OCRv5_{model_type}_rec",
                use_doc_orientation_classify=False,
                use_doc_unwarping=False,
                use_textline_orientation=False,
                device=device,
            )
            downloaded.append(model_type)
        except Exception as e:
            raise RuntimeError(f"Falha ao baixar modelo {model_type}: {e}") from e

    return downloaded


def run_all_checks() -> list[CheckResult]:
    """Executa todas as verificações do sistema."""
    checks = [
        check_python(),
        check_platform(),
        check_ram(),
        check_disk_space(),
        check_paddle(),
        check_paddleocr(),
        check_pypdfium2(),
        check_cuda(),
    ]
    checks.extend(check_models())
    return checks
