"""Bounded read-only business context for scheduling agents."""

from app.core.orchestration.spec import (
    validate_schedule_plan as normalize_schedule_plan,
)
from app.core.orchestration.spec import (
    validate_workflow_spec as normalize_workflow_spec,
)
from app.core.orchestration.spec import workflow_spec_hash


def _untrusted(value):
    if value is None:
        return None
    return {"trust": "untrusted", "value": str(value)[:2000]}


def _page(items, maximum):
    bounded = list(items)[:maximum]
    return {
        "items": bounded,
        "count": len(bounded),
        "truncated": len(items) > maximum,
    }


class ContextService:
    def __init__(self, repository):
        self.repository = repository

    def list_dataflows(self, identity, *, limit=50):
        if limit < 1 or limit > 50:
            raise ValueError("limit must be between 1 and 50")
        allowed = []
        for row in self.repository.list_dataflows():
            domain = row.get("business_domain")
            if (
                "*" not in identity.business_domains
                and domain not in identity.business_domains
            ):
                continue
            allowed.append(
                {
                    "uid": row.get("uid"),
                    "name": row.get("name"),
                    "business_domain": domain,
                    "description": _untrusted(row.get("description")),
                }
            )
        return _page(allowed, limit)

    def describe_dataflow(self, identity, dataflow_uid, *, business_domain):
        identity.require_domain(business_domain)
        row = self.repository.describe_dataflow(dataflow_uid)
        if row.get("business_domain") != business_domain:
            raise PermissionError("dataflow is outside identity scope")
        return {
            "uid": row.get("uid"),
            "name": row.get("name"),
            "business_domain": row.get("business_domain"),
            "status": row.get("status"),
            "description": _untrusted(row.get("description")),
        }

    def get_dataflow_dependencies(self, identity, dataflow_uid, *, business_domain):
        identity.require_domain(business_domain)
        safe = []
        for row in self.repository.get_dataflow_dependencies(dataflow_uid):
            if row.get("business_domain") != business_domain:
                continue
            safe.append(
                {
                    "uid": row.get("uid"),
                    "name": row.get("name"),
                    "relation": row.get("relation"),
                    "business_domain": row.get("business_domain"),
                }
            )
        return _page(safe, 100)

    def get_data_lineage(
        self,
        identity,
        dataflow_uid,
        *,
        business_domain,
        depth=3,
    ):
        identity.require_domain(business_domain)
        if (
            isinstance(depth, bool)
            or not isinstance(depth, int)
            or depth < 1
            or depth > 5
        ):
            raise ValueError("lineage depth must be between 1 and 5")
        safe = []
        for row in self.repository.get_data_lineage(dataflow_uid, depth):
            safe.append(
                {
                    "from_uid": row.get("from_uid"),
                    "to_uid": row.get("to_uid"),
                    "relation": row.get("relation"),
                    "description": _untrusted(row.get("description")),
                }
            )
        return _page(safe, 100)

    def list_datasource_capabilities(self, identity, business_domain):
        identity.require_domain(business_domain)
        safe = []
        for row in self.repository.list_datasource_capabilities(business_domain):
            safe.append(
                {
                    "uid": row.get("uid"),
                    "type": row.get("type"),
                    "purposes": list(row.get("purposes") or [])[:10],
                    "health": row.get("health"),
                    "capacity": {
                        key: value
                        for key, value in dict(row.get("capacity") or {}).items()
                        if key
                        in {
                            "available",
                            "pool_size",
                            "checked_out",
                            "max_concurrency",
                        }
                    },
                }
            )
        return _page(safe, 50)

    def get_datasource_pool_health(
        self,
        identity,
        data_source_uid,
        *,
        business_domain,
    ):
        identity.require_domain(business_domain)
        row = self.repository.get_datasource_pool_health(data_source_uid)
        return {
            "uid": row.get("uid"),
            "health": row.get("health"),
            "capacity": {
                key: value
                for key, value in dict(row.get("capacity") or {}).items()
                if key
                in {
                    "available",
                    "pool_size",
                    "checked_out",
                    "max_concurrency",
                }
            },
        }

    def get_execution_history(
        self,
        identity,
        dataflow_uid,
        *,
        business_domain,
        limit=20,
        days=7,
    ):
        identity.require_domain(business_domain)
        if limit < 1 or limit > 100:
            raise ValueError("limit must be between 1 and 100")
        if days < 1 or days > 30:
            raise ValueError("days must be between 1 and 30")
        safe = []
        for row in self.repository.get_execution_history(
            dataflow_uid,
            limit,
            days,
        ):
            safe.append(
                {
                    "status": row.get("status"),
                    "correlation_id": row.get("correlation_id"),
                    "started_at": row.get("started_at"),
                    "finished_at": row.get("finished_at"),
                    "safe_error": _untrusted(row.get("safe_error")),
                }
            )
        return _page(safe, limit)

    def get_sla_constraints(self, identity, dataflow_uid, *, business_domain):
        identity.require_domain(business_domain)
        row = self.repository.get_sla_constraints(dataflow_uid)
        return {
            key: row.get(key)
            for key in (
                "timezone",
                "max_duration_seconds",
                "deadline",
                "priority",
            )
            if key in row
        }

    def estimate_schedule_capacity(
        self,
        identity,
        *,
        business_domain,
        schedule_plan,
    ):
        identity.require_domain(business_domain)
        plan = normalize_schedule_plan(schedule_plan)
        row = self.repository.estimate_schedule_capacity(business_domain, plan)
        return {
            "feasible": bool(row.get("feasible", False)),
            "required_slots": row.get("required_slots"),
            "available_slots": row.get("available_slots"),
            "warnings": [
                _untrusted(value) for value in list(row.get("warnings") or [])[:20]
            ],
        }

    def validate_workflow_spec(self, identity, workflow_spec):
        del identity
        normalized = normalize_workflow_spec(workflow_spec)
        return {
            "valid": True,
            "workflow_spec": normalized,
            "workflow_hash": workflow_spec_hash(normalized),
        }

    def validate_schedule_plan(self, identity, schedule_plan):
        del identity
        return {
            "valid": True,
            "schedule_plan": normalize_schedule_plan(schedule_plan),
        }

    def simulate_schedule(
        self,
        identity,
        *,
        business_domain,
        schedule_plan,
    ):
        identity.require_domain(business_domain)
        plan = normalize_schedule_plan(schedule_plan)
        row = self.repository.simulate_schedule(business_domain, plan)
        return {
            "next_runs": list(row.get("next_runs") or [])[:20],
            "warnings": [
                _untrusted(value) for value in list(row.get("warnings") or [])[:20]
            ],
        }

    def compare_execution_results(
        self,
        identity,
        *,
        business_domain,
        baseline_execution_id,
        candidate_execution_id,
    ):
        identity.require_domain(business_domain)
        row = self.repository.compare_execution_results(
            baseline_execution_id,
            candidate_execution_id,
        )
        metrics = {
            key: value
            for key, value in dict(row.get("metrics") or {}).items()
            if key
            in {
                "row_count_delta",
                "duration_delta_seconds",
                "error_count_delta",
                "output_hash_match",
            }
            and (value is None or isinstance(value, (bool, int, float)))
        }
        return {
            "equivalent": bool(row.get("equivalent", False)),
            "metrics": metrics,
            "differences": [
                _untrusted(value) for value in list(row.get("differences") or [])[:50]
            ],
        }
