#!/usr/bin/env python3
"""Project, milestone, and cycle operations dispatcher.

All subcommands are cloud-only. The unified client handles tier gating
via require_cloud().

Usage:
    python projects.py list-projects [--active] [--all]
    python projects.py create-project --name NAME [--description DESC]
    python projects.py list-milestones [--all]
    python projects.py create-milestone --name NAME [--project ID] [--target-date DATE]
    python projects.py update-milestone MILESTONE_ID [--name] [--target-date] [--description]
    python projects.py delete-milestone MILESTONE_ID
    python projects.py list-cycles [--active]
"""

import argparse
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
from flydocs_api import get_client, output_json, fail


def cmd_list_projects(args: argparse.Namespace) -> None:
    client = get_client()
    result = client.list_projects(active=args.active, show_all=args.show_all)
    output_json(result)


def cmd_create_project(args: argparse.Namespace) -> None:
    client = get_client()
    result = client.create_project(name=args.name, description=args.description)
    output_json(result)


def cmd_update_project(args: argparse.Namespace) -> None:
    client = get_client()
    if args.name is None and args.description is None and args.state is None:
        raise SystemExit(
            "Nothing to update — pass at least one of --name, --description, --state"
        )
    result = client.update_project(
        ref=args.ref,
        name=args.name,
        description=args.description,
        state=args.state,
    )
    output_json(result)


def cmd_archive_project(args: argparse.Namespace) -> None:
    client = get_client()
    result = client.archive_project(ref=args.ref)
    output_json(result)


def cmd_list_milestones(args: argparse.Namespace) -> None:
    client = get_client()
    result = client.list_milestones(show_all=args.show_all)
    output_json(result)


def cmd_create_milestone(args: argparse.Namespace) -> None:
    client = get_client()
    # Default project from activeProjectId (ADR-011)
    project = args.project
    if not project and client.is_cloud:
        project = client.config.get("activeProjectId")
        if not project:
            ap = client.config.get("activeProjects", [])
            if ap:
                project = ap[0]
    result = client.create_milestone(
        name=args.name,
        project=project,
        target_date=args.target_date,
    )
    output_json(result)


def cmd_update_milestone(args: argparse.Namespace) -> None:
    client = get_client()
    fields: dict = {}
    if args.name is not None:
        fields["name"] = args.name
    if args.target_date is not None:
        fields["targetDate"] = args.target_date
    if args.description is not None:
        fields["description"] = args.description
    if not fields:
        fail("At least one of --name, --target-date, or --description is required")
    result = client.update_milestone(args.milestone_id, **fields)
    output_json(result)


def cmd_delete_milestone(args: argparse.Namespace) -> None:
    client = get_client()
    result = client.delete_milestone(args.milestone_id)
    output_json(result)


def cmd_list_cycles(args: argparse.Namespace) -> None:
    """@deprecated FLY-655: use cmd_list_sprints."""
    print(
        "Note: 'list-cycles' is deprecated — use 'list-sprints' instead.",
        file=sys.stderr,
    )
    client = get_client()
    result = client.list_cycles(active=args.active)
    output_json(result)


def _check_kanban_gating(command_name: str) -> None:
    """FLY-692: Warn when sprint commands are used on Kanban boards."""
    from pathlib import Path
    import json as _json
    config_file = Path(".flydocs/config.json")
    if config_file.exists():
        try:
            config = _json.loads(config_file.read_text())
            contexts = config.get("activeContexts") or config.get("workspace", {}).get("activeContexts", [])
            if contexts and contexts[0].get("boardType") == "kanban":
                fail(
                    f"Sprints are not available on Kanban boards. "
                    f"This board uses column-based workflow.\n"
                    f"Use issues.py list --board active to see board-visible issues."
                )
        except (ValueError, OSError):
            pass


def cmd_list_sprints(args: argparse.Namespace) -> None:
    """
    FLY-656: List sprints for the workspace.

    Defaults to active+future (hides closed/historical). Use --all to see
    everything, --active for only currently-active, --current for just the
    single currently-active sprint.
    """
    _check_kanban_gating("list-sprints")
    client = get_client()
    # Default: active+future unless --all is set
    active = bool(getattr(args, "active", False))
    future = bool(getattr(args, "future", False))
    closed = bool(getattr(args, "closed", False))
    current = bool(getattr(args, "current", False))
    include_all = bool(getattr(args, "show_all", False))

    # If no filters specified and not --all, default to active+future
    if not any([active, future, closed, current, include_all]):
        active = True
        future = True

    result = client.list_sprints(
        active=active,
        future=future,
        closed=closed,
        current=current,
        include_all=include_all,
    )
    output_json(result)


def main() -> None:
    parser = argparse.ArgumentParser(description="FlyDocs project operations")
    sub = parser.add_subparsers(dest="command", required=True)

    # list-projects
    lp = sub.add_parser("list-projects", help="List projects")
    lp.add_argument("--active", action="store_true", help="Active projects only")
    lp.add_argument("--all", action="store_true", dest="show_all",
                     help="Include all projects (bypass label filter)")

    # create-project
    cp = sub.add_parser("create-project", help="Create a project")
    cp.add_argument("--name", required=True, help="Project name")
    cp.add_argument("--description", default=None, help="Project description")

    # update-project (FLY-1073)
    up = sub.add_parser("update-project",
                        help="Rename a project or edit its description")
    up.add_argument("ref", help="Project name or id")
    up.add_argument("--name", default=None, help="New project name")
    up.add_argument("--description", default=None, help="New description")
    up.add_argument("--state", default=None,
                    choices=["active", "completed", "canceled"],
                    help="Lifecycle state")

    # archive-project (FLY-1073)
    ap = sub.add_parser("archive-project",
                        help="Archive a project where the provider supports it")
    ap.add_argument("ref", help="Project name or id")

    # list-milestones
    lm = sub.add_parser("list-milestones", help="List milestones")
    lm.add_argument("--all", action="store_true", dest="show_all",
                     help="Include milestones from all projects")

    # create-milestone
    cm = sub.add_parser("create-milestone", help="Create a milestone")
    cm.add_argument("--name", required=True, help="Milestone name")
    cm.add_argument("--project", default=None, help="Project ID")
    cm.add_argument("--target-date", default=None, dest="target_date",
                     help="Target date (YYYY-MM-DD)")

    # update-milestone
    um = sub.add_parser("update-milestone", help="Update a milestone")
    um.add_argument("milestone_id", help="Milestone ID")
    um.add_argument("--name", default=None, help="New name")
    um.add_argument("--target-date", default=None, dest="target_date",
                     help="New target date (YYYY-MM-DD)")
    um.add_argument("--description", default=None, help="New description")

    # delete-milestone
    dm = sub.add_parser("delete-milestone", help="Delete a milestone")
    dm.add_argument("milestone_id", help="Milestone ID")

    # list-cycles (deprecated — use list-sprints)
    lc = sub.add_parser("list-cycles", help="[deprecated] List cycles — use list-sprints")
    lc.add_argument("--active", action="store_true", help="Active cycles only")

    # FLY-656: list-sprints (canonical)
    ls = sub.add_parser("list-sprints", help="List sprints (active+future by default)")
    ls.add_argument("--active", action="store_true", help="Only currently-active sprints")
    ls.add_argument("--future", action="store_true", help="Only future sprints")
    ls.add_argument("--closed", action="store_true", help="Only closed/historical sprints")
    ls.add_argument("--current", action="store_true", help="Just the single currently-active sprint")
    ls.add_argument("--all", action="store_true", dest="show_all", help="All sprints (including historical)")

    args = parser.parse_args()

    commands = {
        "list-projects": cmd_list_projects,
        "create-project": cmd_create_project,
        "update-project": cmd_update_project,
        "archive-project": cmd_archive_project,
        "list-milestones": cmd_list_milestones,
        "create-milestone": cmd_create_milestone,
        "update-milestone": cmd_update_milestone,
        "delete-milestone": cmd_delete_milestone,
        "list-cycles": cmd_list_cycles,
        "list-sprints": cmd_list_sprints,
    }
    commands[args.command](args)


if __name__ == "__main__":
    main()
