from __future__ import annotations

import types

from oasyce.services.autonomy_service import (
    bootstrap_autonomy_payload,
    configure_autonomy_payload,
    get_autonomy_status_payload,
    quickstart_autonomy_payload,
)
from oasyce.services.inbox import ConfirmationInbox
from oasyce.services.scheduler import SchedulerConfig


class _FakeScheduler:
    def __init__(self) -> None:
        self._config = SchedulerConfig()
        self._running = False
        self._updated = False
        self._run_once_calls = 0

    def get_config(self) -> SchedulerConfig:
        return SchedulerConfig.from_dict(self._config.to_dict())

    def update_config(self, config: SchedulerConfig) -> None:
        self._config = SchedulerConfig.from_dict(config.to_dict())
        self._running = bool(self._config.enabled)
        self._updated = True

    def status(self):
        return {
            "running": self._running,
            "last_run": None,
            "next_run": None,
            "last_result": None,
            "total_runs": 0,
            "total_registered": 0,
            "total_errors": 0,
            "config": self._config.to_dict(),
        }

    def run_once(self):
        self._run_once_calls += 1

        class _Result:
            def to_dict(self_nonlocal):
                return {"scan_count": 1, "register_count": 0, "trade_count": 0, "errors": []}

        return _Result()


def test_quickstart_autonomy_requires_public_beta_doctor_ok(tmp_path):
    scheduler = _FakeScheduler()
    inbox = ConfirmationInbox(data_dir=str(tmp_path))

    payload = quickstart_autonomy_payload(
        scan_paths=["~/Documents"],
        scheduler=scheduler,
        inbox=inbox,
        doctor_runner=lambda: {"status": "error", "checks": []},
    )

    assert payload["ok"] is False
    assert "Public beta gate failed" in payload["error"]
    assert scheduler._updated is False


def test_quickstart_autonomy_sets_scheduler_and_trust(tmp_path):
    scheduler = _FakeScheduler()
    inbox = ConfirmationInbox(data_dir=str(tmp_path))

    payload = quickstart_autonomy_payload(
        scan_paths=["~/Documents", " /tmp/data "],
        interval_hours=12,
        auto_trade=True,
        trade_tags=["data", "model"],
        trade_max_spend=25.0,
        trust_level=2,
        auto_threshold=5.0,
        scheduler=scheduler,
        inbox=inbox,
        doctor_runner=lambda: {"status": "ok", "checks": []},
        module_spec_finder=lambda name: object(),
    )

    assert payload["ok"] is True
    assert payload["running"] is True
    assert payload["summary"]["data_ingress"] == "datavault"
    assert payload["config"]["scan_paths"] == ["~/Documents", "/tmp/data"]
    assert payload["config"]["interval_hours"] == 12
    assert payload["config"]["auto_trade"] is True
    assert payload["config"]["trade_tags"] == ["data", "model"]
    assert payload["config"]["trade_max_spend"] == 25.0
    assert payload["trust_level"] == 2
    assert payload["auto_threshold"] == 5.0


def test_configure_autonomy_updates_trust_and_threshold(tmp_path):
    scheduler = _FakeScheduler()
    inbox = ConfirmationInbox(data_dir=str(tmp_path))

    payload = configure_autonomy_payload(
        interval_hours=8,
        scan_paths=["~/docs"],
        auto_trade=False,
        trade_tags=["text"],
        trade_max_spend=7.5,
        trust_level=1,
        auto_threshold=3.0,
        scheduler=scheduler,
        inbox=inbox,
        module_spec_finder=lambda name: None,
    )

    assert payload["ok"] is True
    assert payload["changed"] is True
    assert payload["data_ingress"] == "builtin_scanner"
    assert payload["config"]["interval_hours"] == 8
    assert payload["config"]["scan_paths"] == ["~/docs"]
    assert payload["config"]["auto_trade"] is False
    assert payload["config"]["trade_tags"] == ["text"]
    assert payload["config"]["trade_max_spend"] == 7.5
    assert payload["trust_level"] == 1
    assert payload["auto_threshold"] == 3.0


def test_get_autonomy_status_payload_reads_scheduler_and_inbox(tmp_path):
    scheduler = _FakeScheduler()
    inbox = ConfirmationInbox(data_dir=str(tmp_path))
    inbox.set_trust_level(2)
    inbox.set_auto_threshold(6.0)

    payload = get_autonomy_status_payload(
        scheduler=scheduler,
        inbox=inbox,
        module_spec_finder=lambda name: object(),
    )

    assert payload["trust_level"] == 2
    assert payload["auto_threshold"] == 6.0
    assert payload["data_ingress"] == "datavault"


def test_bootstrap_autonomy_payload_enables_default_scan_path_and_runs_once(tmp_path):
    scheduler = _FakeScheduler()
    inbox = ConfirmationInbox(data_dir=str(tmp_path))
    docs_dir = tmp_path / "Documents"
    docs_dir.mkdir()

    payload = bootstrap_autonomy_payload(
        scheduler=scheduler,
        inbox=inbox,
        doctor_runner=lambda: {"status": "ok", "checks": []},
        module_spec_finder=lambda name: object(),
        home_dir=tmp_path,
    )

    assert payload["ok"] is True
    assert payload["auto_started"] is True
    assert payload["reason"] == "enabled_default_autonomy"
    assert payload["default_scan_paths"] == [str(docs_dir)]
    assert scheduler._run_once_calls == 1


def test_bootstrap_autonomy_payload_preserves_existing_config(tmp_path):
    scheduler = _FakeScheduler()
    scheduler.update_config(
        SchedulerConfig(
            enabled=False,
            interval_hours=24,
            scan_paths=["/tmp/existing"],
            auto_register=True,
            auto_trade=False,
            trade_tags=[],
            trade_max_spend=10.0,
        )
    )
    inbox = ConfirmationInbox(data_dir=str(tmp_path))

    payload = bootstrap_autonomy_payload(
        scheduler=scheduler,
        inbox=inbox,
        doctor_runner=lambda: {"status": "ok", "checks": []},
        module_spec_finder=lambda name: object(),
        home_dir=tmp_path,
    )

    assert payload["ok"] is True
    assert payload["auto_started"] is False
    assert payload["reason"] == "already_configured"
    assert scheduler._run_once_calls == 0
