from __future__ import annotations

import json
import sys
from pathlib import Path
from typing import Any

from ..errors import QingflowApiError


def load_json_value(path: str, *, option_name: str) -> Any:
    if not path:
        raise QingflowApiError.config_error(f"{option_name} is required")
    if path == "-":
        raw = sys.stdin.read()
    else:
        try:
            raw = Path(path).expanduser().read_text(encoding="utf-8")
        except OSError as exc:
            raise QingflowApiError.config_error(f"failed to read {option_name} from '{path}': {exc}") from exc
    try:
        return json.loads(raw)
    except json.JSONDecodeError as exc:
        raise QingflowApiError.config_error(f"{option_name} must contain valid JSON: {exc}") from exc


def load_json_object(path: str, *, option_name: str) -> dict[str, Any]:
    payload = load_json_value(path, option_name=option_name)
    if not isinstance(payload, dict):
        raise QingflowApiError.config_error(f"{option_name} must be a JSON object")
    return payload


def load_json_list(path: str, *, option_name: str) -> list[Any]:
    payload = load_json_value(path, option_name=option_name)
    if not isinstance(payload, list):
        raise QingflowApiError.config_error(f"{option_name} must be a JSON array")
    return payload


def load_optional_json_object(path: str | None, *, option_name: str) -> dict[str, Any] | None:
    if not path:
        return None
    return load_json_object(path, option_name=option_name)


def load_optional_json_list(path: str | None, *, option_name: str) -> list[Any]:
    if not path:
        return []
    return load_json_list(path, option_name=option_name)
