from __future__ import annotations

from pathlib import Path

from oasyce.services import scheduler as scheduler_module
from oasyce.services.inbox import ConfirmationInbox, TRUST_MANUAL
from oasyce.services.mandate_service import load_mandate, save_mandate, set_mandate_profile
from oasyce.services.scanner import AssetScanner, ScanResult
from oasyce.services.scheduler import AgentScheduler, SchedulerConfig


class _FakeScanner(AssetScanner):
    def __init__(self, results):
        super().__init__()
        self._results = results

    def scan_directory(self, path: str, recursive: bool = True):
        return list(self._results)


def test_scheduler_records_observed_candidate_and_draft_states(tmp_path, monkeypatch):
    target = tmp_path / "repo" / "notes.md"
    target.parent.mkdir(parents=True)
    target.write_text("hello\n", encoding="utf-8")

    results = [
        ScanResult(
            scan_id="scan-1",
            file_path=str(target),
            file_type="md",
            size_bytes=target.stat().st_size,
            suggested_name="Notes",
            suggested_tags=["md", "document"],
            suggested_description="Notes",
            sensitivity="public",
            confidence=0.9,
        )
    ]

    monkeypatch.setattr(scheduler_module, "_scan_with_sdk", lambda path, scanner: None)

    inbox = ConfirmationInbox(data_dir=str(tmp_path))
    inbox.set_trust_level(TRUST_MANUAL)
    scheduler = AgentScheduler(
        SchedulerConfig(enabled=False, scan_paths=[str(tmp_path)], auto_register=True),
        _FakeScanner(results),
        inbox,
        str(tmp_path),
    )

    result = scheduler.run_once()
    status = scheduler.status()
    counts = status["asset_lifecycle"]["counts"]

    assert result.scan_count == 1
    assert counts["observed"] == 0
    assert counts["candidate"] == 0
    assert counts["draft"] == 1
    assert status["asset_lifecycle"]["pricing_counts"]["auto"] == 1
    assert status["asset_lifecycle"]["asset_class_counts"]["generic_asset"] == 1
    assert len(status["asset_lifecycle"]["recent"]) == 1
    assert status["asset_lifecycle"]["recent"][0]["file_path"] == str(target)
    assert status["asset_lifecycle"]["recent"][0]["price_model"] == "auto"
    assert (
        status["asset_lifecycle"]["recent"][0]["recommended_by"]["agent_id"] == "autonomy.scheduler"
    )
    assert status["last_result"]["coordination"]["agent_id"] == "autonomy.scheduler"


def test_scheduler_auto_register_executes_approved_items(tmp_path, monkeypatch):
    target = tmp_path / "repo" / "notes.md"
    target.parent.mkdir(parents=True)
    target.write_text("hello\n", encoding="utf-8")

    results = [
        ScanResult(
            scan_id="scan-1",
            file_path=str(target),
            file_type="md",
            size_bytes=target.stat().st_size,
            suggested_name="Notes",
            suggested_tags=["md", "document"],
            suggested_description="Notes",
            sensitivity="public",
            confidence=0.9,
        )
    ]

    monkeypatch.setattr(scheduler_module, "_scan_with_sdk", lambda path, scanner: None)

    def _fake_execute(item_id, *, inbox, data_dir, actor):
        return inbox.record_execution(
            item_id,
            success=True,
            actor=actor,
            result={"asset_id": "asset_123"},
        )

    monkeypatch.setattr(scheduler_module, "execute_inbox_item", _fake_execute)

    inbox = ConfirmationInbox(data_dir=str(tmp_path))
    inbox.set_trust_level(scheduler_module.TRUST_FULL_AUTO)
    scheduler = AgentScheduler(
        SchedulerConfig(enabled=False, scan_paths=[str(tmp_path)], auto_register=True),
        _FakeScanner(results),
        inbox,
        str(tmp_path),
    )

    result = scheduler.run_once()
    items = inbox.list_all()

    assert result.register_count == 1
    assert len(items) == 1
    assert items[0].execution_status == "succeeded"
    assert items[0].coordination["executed_by"]["agent_id"] == "autonomy.scheduler"


def test_scheduler_respects_mandate_review_boundary(tmp_path, monkeypatch):
    target = tmp_path / "repo" / "data.csv"
    target.parent.mkdir(parents=True)
    target.write_text("x,y\n1,2\n", encoding="utf-8")

    results = [
        ScanResult(
            scan_id="scan-2",
            file_path=str(target),
            file_type="csv",
            size_bytes=target.stat().st_size,
            suggested_name="Data",
            suggested_tags=["csv"],
            suggested_description="Data",
            sensitivity="public",
            confidence=0.95,
        )
    ]

    monkeypatch.setattr(scheduler_module, "_scan_with_sdk", lambda path, scanner: None)
    set_mandate_profile("balanced", data_dir=str(tmp_path))
    current = load_mandate(str(tmp_path))
    save_mandate(
        current.__class__(
            **{
                **current.to_dict(),
                "review_mode": "all_candidates",
            }
        ),
        data_dir=str(tmp_path),
    )

    inbox = ConfirmationInbox(data_dir=str(tmp_path))
    scheduler = AgentScheduler(
        SchedulerConfig(enabled=False, scan_paths=[str(tmp_path)], auto_register=True),
        _FakeScanner(results),
        inbox,
        str(tmp_path),
    )

    scheduler.run_once()
    recent = scheduler.status()["asset_lifecycle"]["recent"][0]

    assert recent["state"] == "draft"
    assert recent["portfolio_policy_reason"] == "mandate_requires_review"
