from __future__ import annotations

from app.models.agent_asset import AgentAsset
from app.schemas.agent_asset import AgentAssetRuleJsonRead, AgentAssetRuleJsonWrite
from app.services.agent_asset_spreadsheet import RISK_RULES_LIBRARY, RULE_LIBRARY_NAMES
from app.services.risk_rule_manifest_normalizer import normalize_risk_rule_manifest


class AgentAssetJsonRuleMixin:
    def _resolve_json_risk_rule_document(self, asset: AgentAsset) -> tuple[str, str]:
        config_json = dict(asset.config_json or {})
        detail_mode = str(config_json.get("detail_mode") or "").strip().lower()
        if detail_mode != "json_risk":
            raise ValueError("当前资产不是 JSON 风险规则。")

        rule_library = str(config_json.get("rule_library") or RISK_RULES_LIBRARY).strip()
        if rule_library not in RULE_LIBRARY_NAMES:
            raise ValueError("规则库目录不合法。")

        rule_document = self._resolve_working_json_risk_rule_document(asset, config_json)
        if not isinstance(rule_document, dict):
            raise ValueError("规则资产缺少 rule_document 配置。")

        file_name = str(rule_document.get("file_name") or "").strip()
        if not file_name:
            raise ValueError("规则资产缺少 JSON 文件名。")
        return rule_library, file_name

    @staticmethod
    def _resolve_working_json_risk_rule_document(
        asset: AgentAsset,
        config_json: dict,
    ) -> dict | None:
        revision = config_json.get("revision_draft")
        if isinstance(revision, dict):
            revision_version = str(revision.get("version") or "").strip()
            working_version = str(asset.working_version or "").strip()
            published_version = str(asset.published_version or "").strip()
            revision_document = revision.get("rule_document")
            if (
                revision_version
                and revision_version == working_version
                and revision_version != published_version
                and isinstance(revision_document, dict)
                and str(revision_document.get("file_name") or "").strip()
            ):
                return revision_document
        return config_json.get("rule_document")

    def read_rule_json(self, asset_id: str) -> AgentAssetRuleJsonRead:
        asset = self.repository.get(asset_id)
        if asset is None:
            raise LookupError("资产不存在。")

        rule_library, file_name = self._resolve_json_risk_rule_document(asset)
        payload = self.rule_library_manager.read_rule_library_json(
            library=rule_library,
            file_name=file_name,
        )
        payload = normalize_risk_rule_manifest(payload)
        return AgentAssetRuleJsonRead(
            file_name=file_name,
            rule_code=str(payload.get("rule_code") or asset.code or ""),
            name=str(payload.get("name") or asset.name or ""),
            description=str(payload.get("description") or asset.description or "").strip(),
            evaluator=str(payload.get("evaluator") or ""),
            ontology_signal=str(payload.get("ontology_signal") or "") or None,
            flow_diagram_svg=str(payload.get("flow_diagram_svg") or "") or None,
            inputs=payload.get("inputs") if isinstance(payload.get("inputs"), dict) else {},
            outcomes=payload.get("outcomes") if isinstance(payload.get("outcomes"), dict) else {},
            payload=payload,
        )

    def write_rule_json(
        self,
        asset_id: str,
        *,
        body: AgentAssetRuleJsonWrite,
        actor: str,
        request_id: str | None = None,
    ) -> AgentAssetRuleJsonRead:
        asset = self.repository.get(asset_id)
        if asset is None:
            raise LookupError("资产不存在。")

        rule_library, file_name = self._resolve_json_risk_rule_document(asset)
        payload = dict(body.payload or {})
        asset_code = str(asset.code or "").strip()
        if asset_code and str(payload.get("rule_code") or "").strip() not in {"", asset_code}:
            raise ValueError("规则 JSON 的 rule_code 必须与资产编码一致。")
        if asset_code and not str(payload.get("rule_code") or "").strip():
            payload["rule_code"] = asset_code

        saved = self.rule_library_manager.write_rule_library_json(
            library=rule_library,
            file_name=file_name,
            payload=payload,
        )
        rule_description = str(saved.get("description") or "").strip()
        if rule_description:
            asset.description = rule_description
        rule_name = str(saved.get("name") or "").strip()
        if rule_name:
            asset.name = rule_name
        risk_category = str(saved.get("risk_category") or "").strip()
        if risk_category:
            config_json = dict(asset.config_json or {})
            config_json["risk_category"] = risk_category
            asset.config_json = config_json
            asset.scenario_json = [risk_category]
        self.audit_service.log_action(
            actor=actor,
            action="update_agent_asset_rule_json",
            resource_type=asset.asset_type,
            resource_id=asset.id,
            before_json={"file_name": file_name},
            after_json={"file_name": file_name, "rule_code": saved.get("rule_code")},
            request_id=request_id,
        )
        self.db.commit()
        return self.read_rule_json(asset_id)
