"""
Сохранение/загрузка глобальных настроек приложения (внешние программы,
производительность, безопасность) в JSON.

Аналогично конфигурации сканирования (пути, слова, опции поиска), которая
сохраняется между запусками через QSettings в MainWindow.
"""
from __future__ import annotations

import json
import os
import shutil
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Optional

from app.config import SETTINGS_FILE


@dataclass
class AppSettings:
    libreoffice_path: Optional[str] = None
    tesseract_path: Optional[str] = None
    max_workers: int = min(32, (os.cpu_count() or 4) * 4)
    per_file_timeout: int = 60
    max_matches_per_word: int = 50
    secure_passes: int = 3


def load_settings() -> AppSettings:
    if not SETTINGS_FILE.exists():
        return _autodetect(AppSettings())
    try:
        data = json.loads(SETTINGS_FILE.read_text(encoding="utf-8"))
        s = AppSettings(**{k: v for k, v in data.items() if k in AppSettings.__dataclass_fields__})
        return _autodetect(s)
    except (OSError, json.JSONDecodeError, TypeError):
        return _autodetect(AppSettings())


def save_settings(s: AppSettings) -> None:
    try:
        SETTINGS_FILE.parent.mkdir(parents=True, exist_ok=True)
        SETTINGS_FILE.write_text(json.dumps(asdict(s), ensure_ascii=False, indent=2), encoding="utf-8")
    except OSError:
        pass


def autodetect_external_programs() -> tuple[Optional[str], Optional[str]]:
    """Возвращает (libreoffice_path, tesseract_path), найденные автоматически.

    Ищет исполняемые файлы в PATH и (для LibreOffice на Windows) в стандартных
    каталогах установки. Возвращает None для программ, которые не найдены.
    Используется кнопками «Определить автоматически» в диалоге параметров.
    """
    lo: Optional[str] = None
    for c in ("soffice", "soffice.exe", "libreoffice"):
        found = shutil.which(c)
        if found:
            lo = found
            break
    if not lo and os.name == "nt":
        for p in (
            r"C:\Program Files\LibreOffice\program\soffice.exe",
            r"C:\Program Files (x86)\LibreOffice\program\soffice.exe",
        ):
            if Path(p).exists():
                lo = p
                break

    ts: Optional[str] = shutil.which("tesseract") or shutil.which("tesseract.exe")
    if not ts and os.name == "nt":
        for p in (
            r"C:\Program Files\Tesseract-OCR\tesseract.exe",
            r"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe",
            r"C:\Tesseract-OCR\tesseract.exe",
            r"D:\Program Files\Tesseract-OCR\tesseract.exe",
        ):
            if Path(p).exists():
                ts = p
                break

    return lo, ts


def _autodetect(s: AppSettings) -> AppSettings:
    """Автоопределение путей к LibreOffice и Tesseract, если они не заданы.
    Вызывает autodetect_external_programs() только если хотя бы один из
    путей отсутствует (избегаем лишнего запуска поиска)."""
    needs_lo = not s.libreoffice_path
    needs_ts = not s.tesseract_path
    if needs_lo or needs_ts:
        lo, ts = autodetect_external_programs()
        if needs_lo:
            s.libreoffice_path = lo
        if needs_ts:
            s.tesseract_path = ts
    return s
