from __future__ import annotations

import importlib.util
from pathlib import Path
from typing import Any, Callable, Dict, Iterable, Optional

from oasyce.services.inbox import ConfirmationInbox, TRUST_SEMI_AUTO
from oasyce.services.public_beta_gate import run_public_beta_doctor
from oasyce.services.scheduler import SchedulerConfig, get_scheduler


def _resolve_data_ingress(
    *,
    module_spec_finder: Callable[[str], Any] = importlib.util.find_spec,
) -> str:
    return "datavault" if module_spec_finder("datavault") else "builtin_scanner"


def _status_payload(
    *,
    scheduler: Any,
    inbox: ConfirmationInbox,
    module_spec_finder: Callable[[str], Any] = importlib.util.find_spec,
) -> Dict[str, Any]:
    status = scheduler.status()
    status["trust_level"] = inbox.get_trust_level()
    status["auto_threshold"] = inbox.get_auto_threshold()
    status["data_ingress"] = _resolve_data_ingress(module_spec_finder=module_spec_finder)
    return status


def _default_bootstrap_scan_paths(home_dir: Optional[Path] = None) -> list[str]:
    home = home_dir or Path.home()
    candidates = [home / "Documents"]
    return [str(path) for path in candidates if path.exists() and path.is_dir()]


def get_autonomy_status_payload(
    *,
    data_dir: Optional[str] = None,
    scheduler: Any = None,
    inbox: Optional[ConfirmationInbox] = None,
    module_spec_finder: Callable[[str], Any] = importlib.util.find_spec,
) -> Dict[str, Any]:
    scheduler = scheduler or get_scheduler(data_dir)
    inbox = inbox or ConfirmationInbox(data_dir=data_dir)
    return _status_payload(
        scheduler=scheduler,
        inbox=inbox,
        module_spec_finder=module_spec_finder,
    )


def configure_autonomy_payload(
    *,
    interval_hours: Optional[int] = None,
    scan_paths: Optional[Iterable[str]] = None,
    auto_trade: Optional[bool] = None,
    trade_tags: Optional[Iterable[str]] = None,
    trade_max_spend: Optional[float] = None,
    trust_level: Optional[int] = None,
    auto_threshold: Optional[float] = None,
    data_dir: Optional[str] = None,
    scheduler: Any = None,
    inbox: Optional[ConfirmationInbox] = None,
    module_spec_finder: Callable[[str], Any] = importlib.util.find_spec,
) -> Dict[str, Any]:
    scheduler = scheduler or get_scheduler(data_dir)
    inbox = inbox or ConfirmationInbox(data_dir=data_dir)
    config = scheduler.get_config()

    changed = False
    if interval_hours is not None:
        config.interval_hours = interval_hours
        changed = True
    if scan_paths is not None:
        config.scan_paths = [str(path).strip() for path in scan_paths if str(path).strip()]
        changed = True
    if auto_trade is not None:
        config.auto_trade = auto_trade
        changed = True
    if trade_tags is not None:
        config.trade_tags = [str(tag).strip() for tag in trade_tags if str(tag).strip()]
        changed = True
    if trade_max_spend is not None:
        config.trade_max_spend = trade_max_spend
        changed = True
    if changed:
        scheduler.update_config(config)

    if trust_level is not None:
        inbox.set_trust_level(trust_level)
    if auto_threshold is not None:
        inbox.set_auto_threshold(auto_threshold)

    return {
        "ok": True,
        "changed": changed or trust_level is not None or auto_threshold is not None,
        **_status_payload(
            scheduler=scheduler,
            inbox=inbox,
            module_spec_finder=module_spec_finder,
        ),
    }


def quickstart_autonomy_payload(
    *,
    scan_paths: Iterable[str],
    interval_hours: int = 24,
    auto_trade: bool = False,
    trade_tags: Optional[Iterable[str]] = None,
    trade_max_spend: float = 10.0,
    trust_level: int = TRUST_SEMI_AUTO,
    auto_threshold: float = 10.0,
    data_dir: Optional[str] = None,
    scheduler: Any = None,
    inbox: Optional[ConfirmationInbox] = None,
    doctor_runner: Callable[..., Dict[str, Any]] = run_public_beta_doctor,
    module_spec_finder: Callable[[str], Any] = importlib.util.find_spec,
) -> Dict[str, Any]:
    normalized_paths = [str(path).strip() for path in scan_paths if str(path).strip()]
    if not normalized_paths:
        return {"ok": False, "error": "Pass at least one scan path for autonomous mode."}

    doctor = doctor_runner()
    if doctor.get("status") == "error":
        return {
            "ok": False,
            "error": "Public beta gate failed. Run `oas doctor --public-beta --json` first.",
            "doctor": doctor,
        }

    scheduler = scheduler or get_scheduler(data_dir)
    inbox = inbox or ConfirmationInbox(data_dir=data_dir)
    config = scheduler.get_config()
    config.interval_hours = interval_hours
    config.scan_paths = normalized_paths
    config.auto_register = True
    config.auto_trade = auto_trade
    config.trade_tags = [str(tag).strip() for tag in (trade_tags or []) if str(tag).strip()]
    config.trade_max_spend = trade_max_spend
    config.enabled = True
    scheduler.update_config(config)
    inbox.set_trust_level(trust_level)
    inbox.set_auto_threshold(auto_threshold)

    return {
        "ok": True,
        "doctor": doctor,
        "summary": {
            "mode": "autonomous_v1",
            "data_ingress": _resolve_data_ingress(module_spec_finder=module_spec_finder),
            "auto_register": True,
            "auto_trade": config.auto_trade,
            "scan_paths": list(config.scan_paths),
            "trade_tags": list(config.trade_tags),
            "trade_max_spend": config.trade_max_spend,
            "trust_level": inbox.get_trust_level(),
            "auto_threshold": inbox.get_auto_threshold(),
        },
        **_status_payload(
            scheduler=scheduler,
            inbox=inbox,
            module_spec_finder=module_spec_finder,
        ),
    }


def bootstrap_autonomy_payload(
    *,
    data_dir: Optional[str] = None,
    scheduler: Any = None,
    inbox: Optional[ConfirmationInbox] = None,
    doctor_runner: Callable[..., Dict[str, Any]] = run_public_beta_doctor,
    module_spec_finder: Callable[[str], Any] = importlib.util.find_spec,
    home_dir: Optional[Path] = None,
) -> Dict[str, Any]:
    scheduler = scheduler or get_scheduler(data_dir)
    inbox = inbox or ConfirmationInbox(data_dir=data_dir)
    config = scheduler.get_config()

    if config.enabled or config.scan_paths:
        return {
            "ok": True,
            "auto_started": False,
            "reason": "already_configured",
            **_status_payload(
                scheduler=scheduler,
                inbox=inbox,
                module_spec_finder=module_spec_finder,
            ),
        }

    scan_paths = _default_bootstrap_scan_paths(home_dir=home_dir)
    if not scan_paths:
        return {
            "ok": True,
            "auto_started": False,
            "reason": "no_default_scan_paths",
            **_status_payload(
                scheduler=scheduler,
                inbox=inbox,
                module_spec_finder=module_spec_finder,
            ),
        }

    payload = quickstart_autonomy_payload(
        scan_paths=scan_paths,
        scheduler=scheduler,
        inbox=inbox,
        doctor_runner=doctor_runner,
        module_spec_finder=module_spec_finder,
    )
    if not payload.get("ok"):
        return {
            "ok": False,
            "auto_started": False,
            "reason": "doctor_failed",
            **payload,
        }

    initial_cycle = None
    initial_cycle_error = None
    try:
        initial_cycle = scheduler.run_once().to_dict()
    except Exception as exc:  # pragma: no cover - defensive guard
        initial_cycle_error = str(exc)

    payload.update(
        {
            "auto_started": True,
            "reason": "enabled_default_autonomy",
            "default_scan_paths": scan_paths,
            "initial_cycle": initial_cycle,
            "initial_cycle_error": initial_cycle_error,
        }
    )
    return payload
