"""Abstract base class for Odoo backends (XML-RPC, REST, etc.).

Defines the contract that all Odoo backend implementations must fulfill.
Shared configuration utilities live here.
"""

import json
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any

CONFIG_DIR = Path.home() / ".cli-anything-odoo_12"
CONFIG_FILE = CONFIG_DIR / "config.json"

DEFAULT_URL = "http://localhost:8069"
DEFAULT_DB = "test"
DEFAULT_USER = "admin"
DEFAULT_PASSWORD = "admin"


def load_config() -> dict:
    """Load saved connection configuration."""
    if CONFIG_FILE.exists():
        try:
            with open(CONFIG_FILE) as f:
                return json.load(f)
        except (json.JSONDecodeError, IOError):
            pass
    return {}


def save_config(config: dict):
    """Save connection configuration."""
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    with open(CONFIG_FILE, "w") as f:
        json.dump(config, f, indent=2)


def get_connection_params(url: str | None = None, db: str | None = None,
                          user: str | None = None, password: str | None = None) -> dict:
    """Resolve connection parameters from args, config, or defaults."""
    cfg = load_config()
    return {
        "url": url or cfg.get("url", DEFAULT_URL),
        "db": db or cfg.get("db", DEFAULT_DB),
        "user": user or cfg.get("user", DEFAULT_USER),
        "password": password or cfg.get("password", DEFAULT_PASSWORD),
    }


class OdooBackend(ABC):
    """Abstract base class defining the Odoo backend interface.

    All backend implementations (XML-RPC, REST) must implement these methods.
    """

    def __init__(self, url: str, db: str, user: str, password: str):
        self.url = url.rstrip("/")
        self.db = db
        self.user = user
        self.password = password
        self.uid: int | None = None

    # ── Authentication ───────────────────────────────────────────

    @abstractmethod
    def authenticate(self) -> int:
        """Authenticate and return uid. Raises RuntimeError on failure."""

    @abstractmethod
    def _ensure_auth(self):
        """Ensure the backend is authenticated."""

    # ── Generic execution ────────────────────────────────────────

    @abstractmethod
    def execute_kw(self, model: str, method: str, args: list,
                   kwargs: dict | None = None) -> Any:
        """Execute a method on an Odoo model."""

    # ── Record CRUD ──────────────────────────────────────────────

    @abstractmethod
    def search(self, model: str, domain: list, limit: int = 0,
               offset: int = 0, order: str = "") -> list[int]:
        ...

    @abstractmethod
    def search_read(self, model: str, domain: list, fields: list[str] | None = None,
                    limit: int = 0, offset: int = 0, order: str = "") -> list[dict]:
        ...

    @abstractmethod
    def read(self, model: str, ids: list[int],
             fields: list[str] | None = None) -> list[dict]:
        ...

    @abstractmethod
    def create(self, model: str, values: dict) -> int:
        ...

    @abstractmethod
    def write(self, model: str, ids: list[int], values: dict) -> bool:
        ...

    @abstractmethod
    def unlink(self, model: str, ids: list[int]) -> bool:
        ...

    @abstractmethod
    def search_count(self, model: str, domain: list) -> int:
        ...

    @abstractmethod
    def fields_get(self, model: str, attributes: list[str] | None = None) -> dict:
        ...

    # ── Module operations ────────────────────────────────────────

    @abstractmethod
    def module_list(self, state: str | None = None) -> list[dict]:
        ...

    @abstractmethod
    def module_info(self, name: str) -> dict | None:
        ...

    @abstractmethod
    def module_install(self, name: str) -> dict:
        ...

    @abstractmethod
    def module_update(self, name: str) -> dict:
        ...

    # ── Database operations ──────────────────────────────────────

    @abstractmethod
    def db_list(self) -> list[str]:
        ...

    @abstractmethod
    def db_create(self, db_name: str, admin_password: str = "admin",
                  demo: bool = False, lang: str = "pt_BR") -> bool:
        ...

    @abstractmethod
    def db_drop(self, db_name: str, admin_password: str = "admin") -> bool:
        ...

    @abstractmethod
    def db_backup(self, db_name: str, output_path: str,
                  admin_password: str = "admin",
                  backup_format: str = "zip") -> dict:
        ...

    @abstractmethod
    def db_restore(self, db_name: str, backup_path: str,
                   admin_password: str = "admin") -> bool:
        ...

    # ── Report generation ────────────────────────────────────────

    @abstractmethod
    def render_report(self, report_name: str, record_ids: list[int],
                      output_path: str) -> dict:
        ...

    # ── Server info ──────────────────────────────────────────────

    @abstractmethod
    def server_version(self) -> str:
        ...

    @abstractmethod
    def check_connection(self) -> dict:
        ...
