"""Track learn workflow result on a plan.

This exec script updates the plan-header metadata block to record the result
of a learn workflow. It sets the learn_status field and optionally records
the learn_plan_issue if a plan was created.

Usage:
    erk exec track-learn-result --plan-id 123 --status completed_no_plan
    erk exec track-learn-result --plan-id 123 --status completed_with_plan --learn-plan 456

Output:
    JSON object with tracking result:
    {
        "success": true,
        "plan_id": "123",
        "learn_status": "completed_no_plan"
    }

Exit Codes:
    0: Success
    1: Error (invalid issue, GitHub failure, validation error, etc.)
"""

import json
from dataclasses import asdict, dataclass

import click

from erk_shared.context.helpers import require_plan_backend, require_repo_root
from erk_shared.gateway.github.metadata.schemas import LearnStatusValue
from erk_shared.plan_store.types import PlanHeaderNotFoundError


@dataclass(frozen=True)
class TrackLearnResultSuccess:
    """Result of successful track-learn-result command."""

    success: bool
    plan_id: str
    learn_status: str
    learn_plan_issue: int | None
    learn_plan_pr: int | None


@dataclass(frozen=True)
class TrackLearnResultError:
    """Error result when tracking fails."""

    success: bool
    error: str
    message: str


# Valid status values for learn result
VALID_RESULT_STATUSES: set[LearnStatusValue] = {
    "completed_no_plan",
    "completed_with_plan",
    "pending_review",
}


@click.command(name="track-learn-result")
@click.option(
    "--plan-id",
    required=True,
    type=str,
    help="Plan identifier (e.g., issue number)",
)
@click.option(
    "--status",
    required=True,
    type=click.Choice(["completed_no_plan", "completed_with_plan", "pending_review"]),
    help="Learn workflow result status",
)
@click.option(
    "--learn-plan",
    type=int,
    help="Learn plan number (required if status is completed_with_plan)",
)
@click.option(
    "--plan-pr",
    type=int,
    help="Learn documentation PR number (required if status is pending_review)",
)
@click.pass_context
def track_learn_result(
    ctx: click.Context,
    *,
    plan_id: str,
    status: str,
    learn_plan: int | None,
    plan_pr: int | None,
) -> None:
    """Track learn workflow result on a plan.

    Updates the plan-header metadata block with the learn workflow result.
    If status is 'completed_with_plan', also records the learn_plan_issue.
    If status is 'pending_review', also records the learn_plan_pr.
    """
    # Validate: completed_with_plan requires --learn-plan
    if status == "completed_with_plan" and learn_plan is None:
        error = TrackLearnResultError(
            success=False,
            error="missing-learn-plan",
            message="--learn-plan is required when status is 'completed_with_plan'",
        )
        click.echo(json.dumps(asdict(error)))
        raise SystemExit(1)

    # completed_no_plan should not have --learn-plan
    if status == "completed_no_plan" and learn_plan is not None:
        error = TrackLearnResultError(
            success=False,
            error="unexpected-learn-plan",
            message="--learn-plan should not be provided when status is 'completed_no_plan'",
        )
        click.echo(json.dumps(asdict(error)))
        raise SystemExit(1)

    # Validate: pending_review requires --plan-pr
    if status == "pending_review" and plan_pr is None:
        error = TrackLearnResultError(
            success=False,
            error="missing-plan-pr",
            message="--plan-pr is required when status is 'pending_review'",
        )
        click.echo(json.dumps(asdict(error)))
        raise SystemExit(1)

    # pending_review should not have --learn-plan
    if status == "pending_review" and learn_plan is not None:
        error = TrackLearnResultError(
            success=False,
            error="unexpected-learn-plan",
            message="--learn-plan should not be provided when status is 'pending_review'",
        )
        click.echo(json.dumps(asdict(error)))
        raise SystemExit(1)

    # completed_with_plan should not have --plan-pr
    if status == "completed_with_plan" and plan_pr is not None:
        error = TrackLearnResultError(
            success=False,
            error="unexpected-plan-pr",
            message="--plan-pr should not be provided when status is 'completed_with_plan'",
        )
        click.echo(json.dumps(asdict(error)))
        raise SystemExit(1)

    # Get dependencies from context
    backend = require_plan_backend(ctx)
    repo_root = require_repo_root(ctx)

    # Cast status to LearnStatusValue (already validated by click.Choice)
    learn_status: LearnStatusValue = status  # type: ignore[assignment]

    # Update plan-header with learn result via PlanBackend
    try:
        backend.update_metadata(
            repo_root,
            plan_id,
            metadata={
                "learn_status": learn_status,
                "learn_plan_issue": learn_plan,
                "learn_plan_pr": plan_pr,
            },
        )
    except PlanHeaderNotFoundError:
        error = TrackLearnResultError(
            success=False,
            error="no-metadata-block",
            message=(
                f"Plan {plan_id} has no plan-header metadata block — cannot update learn status"
            ),
        )
        click.echo(json.dumps(asdict(error)), err=True)
        raise SystemExit(1) from None
    except RuntimeError as e:
        error = TrackLearnResultError(
            success=False,
            error="github-api-failed",
            message=f"Failed to update learn status on plan {plan_id}: {e}",
        )
        click.echo(json.dumps(asdict(error)), err=True)
        raise SystemExit(1) from None

    result = TrackLearnResultSuccess(
        success=True,
        plan_id=plan_id,
        learn_status=status,
        learn_plan_issue=learn_plan,
        learn_plan_pr=plan_pr,
    )

    click.echo(json.dumps(asdict(result), indent=2))
