"""
HubSpot pack smoke test helpers.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Dict, List

from g_gremlin.hubspot import HubSpotClient


@dataclass
class SmokeAssertion:
    type: str
    params: Dict[str, Any]


@dataclass
class SmokeResult:
    assertion: SmokeAssertion
    passed: bool
    detail: str = ""

    @property
    def skipped(self) -> bool:
        return self.detail.startswith("skipped:")

    def to_dict(self) -> Dict[str, Any]:
        return {
            "type": self.assertion.type,
            "params": self.assertion.params,
            "passed": self.passed,
            "detail": self.detail,
            "skipped": self.skipped,
        }


@dataclass
class SmokeReport:
    results: List[SmokeResult]

    @property
    def all_passed(self) -> bool:
        return all(result.passed or result.skipped for result in self.results)

    @property
    def summary(self) -> Dict[str, int]:
        passed = sum(1 for r in self.results if r.passed)
        skipped = sum(1 for r in self.results if r.skipped)
        failed = len(self.results) - passed - skipped
        return {"total": len(self.results), "passed": passed, "failed": failed, "skipped": skipped}

    def to_dict(self) -> Dict[str, Any]:
        return {
            "results": [r.to_dict() for r in self.results],
            "all_passed": self.all_passed,
            "summary": self.summary,
        }


def load_smoke_assertions(pack_yaml_dict: Dict[str, Any]) -> List[SmokeAssertion]:
    smoke_raw = pack_yaml_dict.get("smoke") or []
    if not smoke_raw:
        return []
    options = pack_yaml_dict.get("options") or {}
    workflows_beta = bool(options.get("workflows_beta"))
    assertions: List[SmokeAssertion] = []
    for item in smoke_raw:
        if not isinstance(item, dict):
            assertions.append(SmokeAssertion(type=str(item), params={}))
            continue
        assertion_type = str(item.get("type") or "")
        params = {k: v for k, v in item.items() if k != "type"}
        if assertion_type == "workflow_exists":
            params.setdefault("workflows_beta", workflows_beta)
        assertions.append(SmokeAssertion(type=assertion_type, params=params))
    return assertions


def run_smoke(client: HubSpotClient, assertions: List[SmokeAssertion]) -> SmokeReport:
    results: List[SmokeResult] = []

    for assertion in assertions:
        try:
            result = _run_assertion(client, assertion)
        except Exception as exc:
            result = SmokeResult(assertion=assertion, passed=False, detail=str(exc))
        results.append(result)

    return SmokeReport(results=results)


def _run_assertion(client: HubSpotClient, assertion: SmokeAssertion) -> SmokeResult:
    assertion_type = assertion.type
    params = assertion.params

    if assertion_type == "property_exists":
        object_type = params.get("object_type")
        name = params.get("name")
        if not object_type or name is None:
            return SmokeResult(assertion=assertion, passed=False, detail="missing object_type or name")
        props = client.get_properties(str(object_type))
        exists = any(p.get("name") == name for p in props)
        return SmokeResult(
            assertion=assertion,
            passed=bool(exists),
            detail="" if exists else f"property not found: {name}",
        )

    if assertion_type == "pipeline_has_stages":
        object_type = params.get("object_type")
        pipeline_id = params.get("pipeline_id")
        stages = params.get("stages") or []
        if not object_type or not pipeline_id or not stages:
            return SmokeResult(
                assertion=assertion,
                passed=False,
                detail="missing object_type, pipeline_id, or stages",
            )
        from g_gremlin.hubspot_pipelines import get_pipeline

        payload = get_pipeline(client, str(object_type), str(pipeline_id))
        remote_stages = payload.get("stages", []) or []
        stage_ids = {s.get("id") for s in remote_stages if s.get("id")}
        missing = [s for s in stages if s not in stage_ids]
        if missing:
            return SmokeResult(
                assertion=assertion,
                passed=False,
                detail=f"missing stages: {', '.join(missing)}",
            )
        return SmokeResult(assertion=assertion, passed=True)

    if assertion_type == "list_exists":
        list_id = params.get("list_id")
        if not list_id:
            return SmokeResult(assertion=assertion, passed=False, detail="missing list_id")
        from g_gremlin.hubspot_lists import get_list

        payload = get_list(client, str(list_id))
        exists = bool(payload)
        return SmokeResult(assertion=assertion, passed=exists, detail="" if exists else "list not found")

    if assertion_type == "workflow_exists":
        workflows_beta = bool(params.get("workflows_beta"))
        if not workflows_beta:
            return SmokeResult(assertion=assertion, passed=False, detail="skipped: requires workflows_beta")
        flow_id = params.get("flow_id")
        if not flow_id:
            return SmokeResult(assertion=assertion, passed=False, detail="missing flow_id")
        from g_gremlin.hubspot_workflows import get_flow

        payload = get_flow(client, str(flow_id))
        exists = bool(payload)
        return SmokeResult(assertion=assertion, passed=exists, detail="" if exists else "workflow not found")

    return SmokeResult(assertion=assertion, passed=False, detail=f"unknown assertion type: {assertion_type}")
