"""
Main SEO Campaign Graph
Orchestrates the full SEO campaign workflow with human-in-the-loop interrupts
"""

from typing import Literal
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.base import BaseCheckpointSaver

from state.campaign_state import (
    SEOCampaignState,
    CampaignPhase,
    create_initial_state,
    transition_phase,
)
from nodes.research_node import research_phase
from nodes.content_node import content_phase
from nodes.serp_features_node import serp_optimization_phase
from nodes.link_discovery_node import link_discovery_phase
from nodes.performance_node import generate_report_phase


def check_human_review_required(state: SEOCampaignState) -> Literal["await_approval", "skip_to_report"]:
    """
    Conditional edge: Check if human review is required

    Returns "await_approval" if there are pending approvals,
    otherwise "skip_to_report" to proceed directly to reporting.
    """
    if state.get("requires_human_review") and state.get("pending_approvals"):
        return "await_approval"
    return "skip_to_report"


def check_approval_status(state: SEOCampaignState) -> Literal["execute", "still_pending", "all_rejected"]:
    """
    Conditional edge: Check approval status after human review

    Returns:
    - "execute" if any opportunities were approved
    - "still_pending" if still awaiting approvals
    - "all_rejected" if all were rejected
    """
    pending_approvals = state.get("pending_approvals", [])
    link_opps = state.get("link_opportunities", [])

    # Check if still has pending items
    pending_count = len([o for o in pending_approvals if o.get("status") == "pending"])
    if pending_count > 0:
        return "still_pending"

    # Check if any were approved
    approved_count = len([o for o in link_opps if o.get("status") == "approved"])
    if approved_count > 0:
        return "execute"

    return "all_rejected"


async def await_human_approval(state: SEOCampaignState) -> SEOCampaignState:
    """
    Human approval interrupt node

    This node is configured as an interrupt point. When the graph reaches this node,
    execution pauses and waits for human input via the resume API.

    The human can:
    - Approve opportunities (set status to "approved", optionally edit pitch)
    - Reject opportunities (set status to "rejected", provide reason)

    After human input, the graph resumes and this node processes the updated state.
    """
    print(f"[HumanApproval] Awaiting approval for {len(state.get('pending_approvals', []))} opportunities")

    # Update pending approvals from link opportunities
    # (Human input will have modified the link_opportunities list)
    link_opps = state.get("link_opportunities", [])

    approved = [o for o in link_opps if o.get("status") == "approved"]
    rejected = [o for o in link_opps if o.get("status") == "rejected"]
    still_pending = [o for o in link_opps if o.get("status") == "pending"]

    state["links_approved"] = len(approved)
    state["pending_approvals"] = still_pending

    # If all processed, clear the review flag
    if not still_pending:
        state["requires_human_review"] = False

    print(f"[HumanApproval] Approved: {len(approved)}, Rejected: {len(rejected)}, Still pending: {len(still_pending)}")

    return state


async def execute_approved_outreach(state: SEOCampaignState) -> SEOCampaignState:
    """
    Execute approved link outreach

    Only runs after human approval. Sends outreach emails for approved opportunities.
    """
    print(f"[ExecuteOutreach] Executing outreach for approved opportunities")

    link_opps = state.get("link_opportunities", [])
    approved = [o for o in link_opps if o.get("status") == "approved"]

    # TODO: Integrate with email service for actual outreach
    # For now, just mark as executed
    for opp in approved:
        opp["status"] = "executed"
        opp["executed_at"] = __import__("datetime").datetime.utcnow().isoformat()

    print(f"[ExecuteOutreach] Executed {len(approved)} outreach campaigns")

    # Transition to report
    state = transition_phase(state, CampaignPhase.REPORT)

    return state


def create_seo_campaign_graph(checkpointer: BaseCheckpointSaver | None = None):
    """
    Create the main SEO campaign workflow graph

    Phases:
    1. Research - Gather GSC data, competitors, SERP features
    2. Content - Prioritize and queue content generation
    3. SERP Features - Queue optimizations for snippets, PAA, AI Overviews
    4. Link Discovery - Find white-hat link opportunities
    5. Human Review (INTERRUPT) - Pause for human approval of link opportunities
    6. Execute - Send approved outreach
    7. Report - Generate final campaign report

    The graph uses interrupt_before on the human_review node, allowing
    campaigns to pause and resume after human approval.
    """
    # Create state graph
    graph = StateGraph(SEOCampaignState)

    # Add all phase nodes
    graph.add_node("research", research_phase)
    graph.add_node("content", content_phase)
    graph.add_node("serp_features", serp_optimization_phase)
    graph.add_node("link_discovery", link_discovery_phase)
    graph.add_node("human_review", await_human_approval)
    graph.add_node("execute_outreach", execute_approved_outreach)
    graph.add_node("report", generate_report_phase)

    # Define edges - linear flow with conditional branches
    graph.add_edge(START, "research")
    graph.add_edge("research", "content")
    graph.add_edge("content", "serp_features")
    graph.add_edge("serp_features", "link_discovery")

    # After link discovery, check if human review is needed
    graph.add_conditional_edges(
        "link_discovery",
        check_human_review_required,
        {
            "await_approval": "human_review",
            "skip_to_report": "report",
        }
    )

    # After human review, check what to do next
    graph.add_conditional_edges(
        "human_review",
        check_approval_status,
        {
            "execute": "execute_outreach",
            "still_pending": END,  # Pause - will resume when more approvals come in
            "all_rejected": "report",  # Skip execution, go to report
        }
    )

    # After execution, go to report
    graph.add_edge("execute_outreach", "report")

    # Report is the final node
    graph.add_edge("report", END)

    # Compile with checkpointer and interrupt configuration
    compiled = graph.compile(
        checkpointer=checkpointer,
        interrupt_before=["human_review"],  # Pause BEFORE human review
    )

    return compiled


# Convenience function to create and run a new campaign
async def run_campaign(
    site_id: str,
    campaign_type: str = "zero_click_authority",
    config: dict | None = None,
    checkpointer: BaseCheckpointSaver | None = None,
) -> SEOCampaignState:
    """
    Create and run a new SEO campaign

    Args:
        site_id: The site ID to run the campaign for
        campaign_type: Type of campaign (zero_click_authority, link_building, etc.)
        config: Optional campaign configuration
        checkpointer: Optional checkpointer for state persistence

    Returns:
        Final campaign state (or paused state if awaiting human review)
    """
    import uuid

    # Create initial state
    campaign_id = str(uuid.uuid4())
    initial_state = create_initial_state(
        site_id=site_id,
        campaign_id=campaign_id,
        campaign_type=campaign_type,
        config=config or {},
    )

    # Create graph
    graph = create_seo_campaign_graph(checkpointer)

    # Run until completion or interrupt
    thread_config = {"configurable": {"thread_id": campaign_id}}

    final_state = await graph.ainvoke(initial_state, thread_config)

    return final_state


async def resume_campaign(
    campaign_id: str,
    updated_state: SEOCampaignState,
    checkpointer: BaseCheckpointSaver,
) -> SEOCampaignState:
    """
    Resume a paused campaign after human approval

    Args:
        campaign_id: The campaign ID to resume
        updated_state: State with updated approvals
        checkpointer: Checkpointer with persisted state

    Returns:
        Final campaign state (or paused state if still awaiting approvals)
    """
    graph = create_seo_campaign_graph(checkpointer)

    thread_config = {"configurable": {"thread_id": campaign_id}}

    # Resume with updated state
    final_state = await graph.ainvoke(updated_state, thread_config)

    return final_state
