from __future__ import annotations

import json
from copy import deepcopy
from pathlib import Path
from typing import Any


APP_ROOT = Path(__file__).resolve().parent.parent
CONFIG_PATH = APP_ROOT / "app_config.json"


DEFAULT_CONFIG: dict[str, Any] = {
    "camera": {
        "index": 0,
        "width": 1920,
        "height": 1080,
        "fps": 30,
        "backend": "auto",
        "rotation_degrees": 0,
        "properties": {
            "brightness": None,
            "contrast": None,
            "saturation": None,
            "hue": None,
            "gain": None,
            "exposure": None,
            "sharpness": None,
            "auto_exposure": None,
            "focus": None,
            "auto_focus": None,
        },
    },
    "detection": {
        "model_path": "models/best.pt",
        "confidence_threshold": 0.25,
        "mode": "best",
        "frame_stride": 5,
        "image_size": 640,
        "device": "cpu",
    },
    "ocr": {
        "enabled": True,
        "engine": "tesseract",
        "language": "eng",
        "tesseract_cmd": None,
        "psm": 6,
        "margin": 0,
        "threshold": True,
        "paddle_threshold": False,
        "scale": 2.0,
        "config": "",
        "use_angle_cls": True,
        "paddle": {
            "enable_mkldnn": False,
            "lang": "en",
            "use_doc_orientation_classify": False,
            "use_doc_unwarping": False,
            "use_textline_orientation": False,
        },
    },
    "capture": {
        "photos_dir": "captures/photos",
        "videos_dir": "captures/videos",
        "image_extension": "jpg",
        "video_extension": "mp4",
        "video_codec": "mp4v",
    },
    "display": {
        "show_fps": True,
    },
    "label_data": {
        "model_min_score": 0.72,
        "color_min_score": 0.72,
        "models": ["Regius", "Duvell"],
        "colors": ["T-NF-BLK-OUT-BST-G", "T-BLK-G"],
    },
}


def deep_merge(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
    result = deepcopy(base)
    for key, value in override.items():
        if isinstance(value, dict) and isinstance(result.get(key), dict):
            result[key] = deep_merge(result[key], value)
        else:
            result[key] = value
    return result


class AppConfig:
    def __init__(self, path: Path = CONFIG_PATH) -> None:
        self.path = path
        self.data = self.load()

    def load(self) -> dict[str, Any]:
        if not self.path.exists():
            self.path.parent.mkdir(parents=True, exist_ok=True)
            self.save(DEFAULT_CONFIG)
            return deepcopy(DEFAULT_CONFIG)

        with self.path.open("r", encoding="utf-8") as config_file:
            loaded = json.load(config_file)
        return deep_merge(DEFAULT_CONFIG, loaded)

    def save(self, data: dict[str, Any] | None = None) -> None:
        if data is not None:
            self.data = data
        self.path.parent.mkdir(parents=True, exist_ok=True)
        with self.path.open("w", encoding="utf-8") as config_file:
            json.dump(self.data, config_file, indent=2, ensure_ascii=False)
            config_file.write("\n")

    def resolve_path(self, configured_path: str) -> Path:
        path = Path(configured_path)
        if path.is_absolute():
            return path
        return APP_ROOT / path
