from __future__ import annotations

import copy
from datetime import datetime
from typing import Any

from src.strategy_spec_service import (
    build_promotion_state,
    normalize_compile_target,
)


def compile_custom_strategy_artifact(
    *,
    strategy_id: str,
    name: str,
    document: str,
    runtime_template: dict[str, Any],
    compile_target: str,
) -> dict[str, Any]:
    artifact_type = normalize_compile_target(compile_target)
    if artifact_type == "plugin":
        from src.strategy_code_generator import StrategyCodeGenerator

        result = StrategyCodeGenerator().generate(
            document,
            strategy_id=strategy_id,
            display_name=name,
        )
        if not bool(result.get("valid", False)):
            return {
                "success": False,
                "artifact_type": "plugin",
                "error": "插件策略编译失败",
                "errors": result.get("errors", []),
                "code": result.get("code", ""),
            }
        return {
            "success": True,
            "artifact_type": "plugin",
            "template": {},
            "artifact_ref": {
                "entrypoint": f"strategies.{strategy_id}",
                "file_path": str(result.get("file_path", "")),
                "manifest_path": str(result.get("manifest_path", "")),
            },
            "codegen": result,
        }
    return {
        "success": True,
        "artifact_type": "template",
        "template": copy.deepcopy(runtime_template)
        if isinstance(runtime_template, dict)
        else {},
        "artifact_ref": {},
        "codegen": {},
    }


def register_custom_strategy_asset(
    state: dict[str, Any],
    *,
    strategy_id: str,
    name: str,
    document: str,
    base_engine: str,
    optimized: dict[str, Any],
    evaluation: dict[str, Any],
    developer_agent: dict[str, Any],
    temp_model: str,
    runtime_template: dict[str, Any],
    artifact_type: str = "template",
    artifact_ref: dict[str, Any] | None = None,
    strategy_spec: dict[str, Any] | None = None,
    validation_report: dict[str, Any] | None = None,
    optimize_llm: dict[str, Any] | None = None,
    evaluate_llm: dict[str, Any] | None = None,
    now_iso: str | None = None,
) -> dict[str, Any]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    created_at = str(
        now_iso
        or datetime.now().astimezone().isoformat(timespec="seconds")
    )
    normalized_artifact_type = normalize_compile_target(
        artifact_type,
        base_engine=base_engine,
    )
    artifact_ref_payload = (
        copy.deepcopy(artifact_ref)
        if isinstance(artifact_ref, dict)
        else {}
    )
    strategies[strategy_id] = {
        "display_name": name,
        "enabled": True,
        "is_custom": True,
        "lifecycle_stage": "marketplace",
        "base_engine": base_engine,
        "source_document": document,
        "optimized": optimized if isinstance(optimized, dict) else {},
        "evaluation": evaluation if isinstance(evaluation, dict) else {},
        "developer_agent": developer_agent if isinstance(developer_agent, dict) else {},
        "temp_model": str(temp_model or ""),
        "generation_trace": {
            "optimizer_llm": optimize_llm if isinstance(optimize_llm, dict) else {},
            "evaluator_llm": evaluate_llm if isinstance(evaluate_llm, dict) else {},
        },
        "artifact_type": normalized_artifact_type,
        "artifact_ref": artifact_ref_payload,
        "default_mode": "plugin" if normalized_artifact_type == "plugin" else "asset",
        "trust_level": "sandbox",
        "entrypoint": str(artifact_ref_payload.get("entrypoint", "") or ""),
        "strategy_spec": (
            copy.deepcopy(strategy_spec)
            if isinstance(strategy_spec, dict)
            else {}
        ),
        "validation_report": (
            copy.deepcopy(validation_report)
            if isinstance(validation_report, dict)
            else {}
        ),
        "promotion_state": build_promotion_state(
            lifecycle_stage="marketplace",
            review_status="pending",
        ),
        "template": runtime_template if isinstance(runtime_template, dict) else {},
        "versions": [
            {
                "version": "1.0.0",
                "note": f"generated_from_strategy_custom:{normalized_artifact_type}",
                "published_at": created_at,
            }
        ],
        "current_version": "1.0.0",
        "created_at": created_at,
        "review_status": "pending",
        "review_source": "custom_draft",
        "review_submitted_at": created_at,
    }
    payload["strategies"] = strategies
    return payload


def approve_strategy_market_asset(
    state: dict[str, Any],
    *,
    strategy_id: str,
    reviewer: str,
    notes: str,
    reviewed_at: str | None = None,
) -> tuple[dict[str, Any], str]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    row = strategies.get(strategy_id, {})
    if not isinstance(row, dict) or not row:
        raise KeyError(f"未找到策略: {strategy_id}")
    ts = str(reviewed_at or datetime.now().astimezone().isoformat(timespec="seconds"))
    current_stage = str(row.get("lifecycle_stage", "") or "sandbox")
    row["lifecycle_stage"] = "marketplace"
    row["review_status"] = "approved"
    row["reviewed_by"] = reviewer or "admin"
    row["review_notes"] = notes
    row["reviewed_at"] = ts
    row["promotion_state"] = build_promotion_state(
        lifecycle_stage="marketplace",
        review_status="approved",
    )
    strategies[strategy_id] = row
    payload["strategies"] = strategies
    return payload, current_stage


def reject_strategy_market_asset(
    state: dict[str, Any],
    *,
    strategy_id: str,
    reviewer: str,
    reason: str,
    reviewed_at: str | None = None,
) -> tuple[dict[str, Any], str]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    row = strategies.get(strategy_id, {})
    if not isinstance(row, dict) or not row:
        raise KeyError(f"未找到策略: {strategy_id}")
    ts = str(reviewed_at or datetime.now().astimezone().isoformat(timespec="seconds"))
    current_stage = str(row.get("lifecycle_stage", "") or "sandbox")
    row["lifecycle_stage"] = "marketplace"
    row["review_status"] = "rejected"
    row["reviewed_by"] = reviewer or "admin"
    row["review_notes"] = reason
    row["reviewed_at"] = ts
    row["review_rejected_at"] = ts
    row["promotion_state"] = build_promotion_state(
        lifecycle_stage="marketplace",
        review_status="rejected",
    )
    strategies[strategy_id] = row
    payload["strategies"] = strategies
    return payload, current_stage


def request_strategy_market_revision(
    state: dict[str, Any],
    *,
    strategy_id: str,
    reviewer: str,
    feedback: str,
    reviewed_at: str | None = None,
) -> tuple[dict[str, Any], str]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    row = strategies.get(strategy_id, {})
    if not isinstance(row, dict) or not row:
        raise KeyError(f"未找到策略: {strategy_id}")
    ts = str(reviewed_at or datetime.now().astimezone().isoformat(timespec="seconds"))
    current_stage = str(row.get("lifecycle_stage", "") or "sandbox")
    row["lifecycle_stage"] = "marketplace"
    row["review_status"] = "needs_revision"
    row["reviewed_by"] = reviewer or "admin"
    row["review_notes"] = feedback
    row["reviewed_at"] = ts
    row["review_revision_requested_at"] = ts
    row["promotion_state"] = build_promotion_state(
        lifecycle_stage="marketplace",
        review_status="needs_revision",
    )
    strategies[strategy_id] = row
    payload["strategies"] = strategies
    return payload, current_stage


def withdraw_strategy_market_asset(
    state: dict[str, Any],
    *,
    strategy_id: str,
    reviewer: str,
    notes: str,
    reviewed_at: str | None = None,
) -> tuple[dict[str, Any], str]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    row = strategies.get(strategy_id, {})
    if not isinstance(row, dict) or not row:
        raise KeyError(f"未找到策略: {strategy_id}")
    ts = str(reviewed_at or datetime.now().astimezone().isoformat(timespec="seconds"))
    current_stage = str(row.get("lifecycle_stage", "") or "sandbox")
    row["lifecycle_stage"] = "marketplace"
    row["review_status"] = "pending"
    row["reviewed_by"] = reviewer or "admin"
    row["review_notes"] = notes or str(row.get("review_notes", "") or "")
    row["reviewed_at"] = ts
    row["review_withdrawn_at"] = ts
    row["promotion_state"] = build_promotion_state(
        lifecycle_stage="marketplace",
        review_status="pending",
    )
    strategies[strategy_id] = row
    payload["strategies"] = strategies
    return payload, current_stage


def promote_strategy_market_asset_to_paper(
    state: dict[str, Any],
    *,
    strategy_id: str,
    promoted_at: str | None = None,
) -> tuple[dict[str, Any], str]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    row = strategies.get(strategy_id, {})
    if not isinstance(row, dict) or not row:
        raise KeyError(f"未找到策略: {strategy_id}")
    ts = str(promoted_at or datetime.now().astimezone().isoformat(timespec="seconds"))
    current_stage = str(row.get("lifecycle_stage", "") or "sandbox")
    row["lifecycle_stage"] = "paper"
    row["enabled"] = True
    row["promoted_to_paper_at"] = ts
    row["promotion_state"] = build_promotion_state(
        lifecycle_stage="paper",
        review_status=str(row.get("review_status", "pending") or "pending"),
        promoted_at=ts,
    )
    strategies[strategy_id] = row
    payload["strategies"] = strategies
    return payload, current_stage


def submit_review_entry(
    strategy_id: str,
    *,
    source: str,
    sandbox_result: dict[str, Any] | None = None,
    code: str = "",
) -> dict[str, Any]:
    try:
        from src.strategy_review_board import StrategyReviewBoard

        board = StrategyReviewBoard()
        existing = board.get(strategy_id)
        if existing is not None:
            return {
                "available": True,
                "submitted": False,
                "status": existing.status,
            }
        entry = board.submit(
            strategy_id,
            source=source,
            code=code,
            sandbox_result=sandbox_result if isinstance(sandbox_result, dict) else None,
        )
        return {
            "available": True,
            "submitted": True,
            "status": entry.status,
        }
    except Exception as exc:
        return {
            "available": False,
            "submitted": False,
            "status": "unavailable",
            "error": str(exc),
        }


def approve_review_entry(
    strategy_id: str,
    *,
    reviewer: str,
    notes: str,
    source: str,
    sandbox_result: dict[str, Any] | None = None,
    code: str = "",
) -> dict[str, Any]:
    try:
        from src.strategy_review_board import StrategyReviewBoard

        board = StrategyReviewBoard()
        if board.get(strategy_id) is None:
            board.submit(
                strategy_id,
                source=source,
                code=code,
                sandbox_result=sandbox_result if isinstance(sandbox_result, dict) else None,
            )
        entry = board.approve(strategy_id, reviewer=reviewer, notes=notes)
        return {
            "available": True,
            "approved": True,
            "status": entry.status,
        }
    except Exception as exc:
        return {
            "available": False,
            "approved": False,
            "status": "unavailable",
            "error": str(exc),
        }


def reject_review_entry(
    strategy_id: str,
    *,
    reviewer: str,
    reason: str,
    source: str,
    sandbox_result: dict[str, Any] | None = None,
    code: str = "",
) -> dict[str, Any]:
    try:
        from src.strategy_review_board import StrategyReviewBoard

        board = StrategyReviewBoard()
        if board.get(strategy_id) is None:
            board.submit(
                strategy_id,
                source=source,
                code=code,
                sandbox_result=sandbox_result if isinstance(sandbox_result, dict) else None,
            )
        entry = board.reject(strategy_id, reviewer=reviewer, reason=reason)
        return {
            "available": True,
            "rejected": True,
            "status": entry.status,
        }
    except Exception as exc:
        return {
            "available": False,
            "rejected": False,
            "status": "unavailable",
            "error": str(exc),
        }


def request_review_revision(
    strategy_id: str,
    *,
    reviewer: str,
    feedback: str,
    source: str,
    sandbox_result: dict[str, Any] | None = None,
    code: str = "",
) -> dict[str, Any]:
    try:
        from src.strategy_review_board import StrategyReviewBoard

        board = StrategyReviewBoard()
        if board.get(strategy_id) is None:
            board.submit(
                strategy_id,
                source=source,
                code=code,
                sandbox_result=sandbox_result if isinstance(sandbox_result, dict) else None,
            )
        entry = board.request_revision(strategy_id, reviewer=reviewer, feedback=feedback)
        return {
            "available": True,
            "requested": True,
            "status": entry.status,
        }
    except Exception as exc:
        return {
            "available": False,
            "requested": False,
            "status": "unavailable",
            "error": str(exc),
        }


def withdraw_review_entry(
    strategy_id: str,
    *,
    reviewer: str,
    notes: str,
    source: str,
    sandbox_result: dict[str, Any] | None = None,
    code: str = "",
) -> dict[str, Any]:
    try:
        from src.strategy_review_board import StrategyReviewBoard

        board = StrategyReviewBoard()
        if board.get(strategy_id) is None:
            board.submit(
                strategy_id,
                source=source,
                code=code,
                sandbox_result=sandbox_result if isinstance(sandbox_result, dict) else None,
            )
        entry = board.reopen_pending(strategy_id, reviewer=reviewer, notes=notes)
        return {
            "available": True,
            "withdrawn": True,
            "status": entry.status,
        }
    except Exception as exc:
        return {
            "available": False,
            "withdrawn": False,
            "status": "unavailable",
            "error": str(exc),
        }


def build_strategy_review_explanation(
    state: dict[str, Any],
    *,
    strategy_id: str,
) -> dict[str, Any]:
    payload = state if isinstance(state, dict) else {}
    strategies = (
        payload.get("strategies", {})
        if isinstance(payload.get("strategies", {}), dict)
        else {}
    )
    row = strategies.get(strategy_id, {})
    if not isinstance(row, dict) or not row:
        raise KeyError(f"未找到策略: {strategy_id}")
    review_status = str(row.get("review_status", "pending") or "pending").strip().lower()
    lifecycle_stage = str(row.get("lifecycle_stage", "marketplace") or "marketplace").strip().lower()
    validation = row.get("validation_report", {}) if isinstance(row.get("validation_report", {}), dict) else {}
    advice = str(validation.get("advice", "") or row.get("review_notes", "") or "").strip()
    blockers: list[str] = []
    if review_status == "pending":
        blockers.append("尚未完成人工审核")
    elif review_status == "needs_revision":
        blockers.append("需要先按审核意见补充或修改策略")
    elif review_status == "rejected":
        blockers.append("策略已被驳回，需修正后重新提交")
    if str(validation.get("risk", "") or "").strip().lower() != "pass":
        blockers.append("风控约束仍需补充或确认")
    if lifecycle_stage != "paper" and review_status == "approved":
        blockers.append("已通过审核，下一步应晋级到 Paper")
    next_action = "等待审核"
    if review_status == "approved":
        next_action = "晋级到 Paper"
    elif review_status == "needs_revision":
        next_action = "按意见修改后重新提交审核"
    elif review_status == "rejected":
        next_action = "修正策略并重新提交"
    explanation = {
        "strategy_id": strategy_id,
        "name": str(row.get("display_name", strategy_id) or strategy_id),
        "lifecycle_stage": lifecycle_stage,
        "review_status": review_status,
        "reviewed_by": str(row.get("reviewed_by", "") or ""),
        "reviewed_at": str(row.get("reviewed_at", "") or ""),
        "review_notes": str(row.get("review_notes", "") or ""),
        "validation_status": str(validation.get("status", "") or ""),
        "risk_status": str(validation.get("risk", "") or ""),
        "llm_verdict": str(validation.get("llm_verdict", "") or ""),
        "blockers": blockers,
        "next_action": next_action,
        "summary": advice or "当前策略已进入集市流程，但仍需按审核状态继续推进。",
    }
    return explanation


def is_review_approved(strategy_id: str) -> bool:
    try:
        from src.strategy_review_board import StrategyReviewBoard

        return StrategyReviewBoard().is_approved(strategy_id)
    except Exception:
        return False
