#!/usr/bin/env python3
"""
client_generate.py — CLI for client video generation workflow.

Commands:
    status    Show sequence status for a project
    grid      Generate a start frame exploration grid
    pick      Extract a cell from a grid as start frame
    generate  Generate video for a sequence
    approve   Approve a sequence's output
    init      Initialize sequence state from plan

Usage:
    python tools/client_generate.py status driver-beware
    python tools/client_generate.py grid driver-beware SEQ01
    python tools/client_generate.py pick driver-beware SEQ01 --quadrant top_left
    python tools/client_generate.py generate driver-beware SEQ08
    python tools/client_generate.py generate driver-beware SEQ08 --mode individual
    python tools/client_generate.py approve driver-beware SEQ08
"""

import argparse
import logging
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


# TODO(phase-21-22): every subcommand below references a deleted
# substrate — `tools.client_sequence_runner.ClientSequenceRunner` was
# removed (its capability is being absorbed into EpisodeRunner per CP-10),
# and `recoil.pipeline._lib.client_bridge.init_sequence_state` does not
# exist (client_bridge.py exposes only stateless storyboard/bible loaders).
# Each cmd_* below preserves its argparse contract so the CLI still parses,
# but raises NotImplementedError until the client-workflow surface is
# rewired to EpisodeRunner / dispatch().


def cmd_status(args):
    # TODO(phase-21-22): rewire to EpisodeRunner sequence-status query
    #   from tools.client_sequence_runner import ClientSequenceRunner
    #   runner = ClientSequenceRunner(args.project, args.episode)
    #   runner.print_status()
    raise NotImplementedError(
        "rewire to EpisodeRunner — phase-21-22 deferred (client_sequence_runner removed)"
    )


def cmd_init(args):
    # TODO(phase-21-22): rewire to EpisodeRunner.init_scene + persistence.save_scene
    # (or a future client_bridge.init_sequence_state if/when one is added).
    #   from recoil.pipeline._lib.client_bridge import init_sequence_state
    #   state = init_sequence_state(args.project, args.episode)
    #   print(f"Initialized {len(state)} sequences for {args.project}")
    raise NotImplementedError(
        "rewire to EpisodeRunner.init_scene — phase-21-22 deferred "
        "(client_bridge.init_sequence_state does not exist)"
    )


def cmd_grid(args):
    # TODO(phase-21-22): rewire to dispatch('image_t2i', ...) for grid exploration
    #   from tools.client_sequence_runner import ClientSequenceRunner
    #   runner = ClientSequenceRunner(args.project, args.episode)
    #   result = runner.explore_grid(
    #       seq_id=args.seq_id,
    #       prompt=args.prompt,
    #       grid_size=args.grid_size,
    #       model=args.model or "gemini-3.1-flash-image-preview",
    #   )
    #   if result.success:
    #       print(f"Grid saved: {result.output_path}")
    #       print(f"Cost: ${result.cost_usd:.3f}")
    #       print(f"Next: python tools/client_generate.py pick {args.project} {args.seq_id} --quadrant <tl|tr|bl|br>")
    #   else:
    #       print(f"Grid generation failed: {result.error}")
    #       sys.exit(1)
    raise NotImplementedError(
        "rewire to dispatch('image_t2i', ...) — phase-21-22 deferred "
        "(client_sequence_runner removed)"
    )


def cmd_pick(args):
    # TODO(phase-21-22): rewire to a grid-cell extractor reachable through
    # the post-CP-5 entry points (pure I/O — likely belongs in a tools/
    # helper independent of the dispatch surface).
    #   from tools.client_sequence_runner import ClientSequenceRunner
    #   runner = ClientSequenceRunner(args.project, args.episode)
    #   start_frame = runner.pick_cell(
    #       seq_id=args.seq_id,
    #       quadrant=args.quadrant,
    #       grid_size=args.grid_size,
    #   )
    #   print(f"Start frame saved: {start_frame}")
    #   print(f"Next: python tools/client_generate.py generate {args.project} {args.seq_id}")
    raise NotImplementedError(
        "rewire to grid-cell extractor — phase-21-22 deferred "
        "(client_sequence_runner removed)"
    )


def cmd_generate(args):
    # TODO(phase-21-22): rewire to EpisodeRunner.run_scene (which composes
    # dispatch('video_i2v', ...) per beat). The prompt-override + per-shot
    # mode contract here predates the Take/Workflow model — translation
    # may need a small adapter on top of EpisodeRunner.
    #   from tools.client_sequence_runner import ClientSequenceRunner
    #   runner = ClientSequenceRunner(args.project, args.episode)
    #
    #   # Parse prompt overrides: "2:new prompt,4:another prompt"
    #   prompt_overrides = None
    #   if args.shot_override:
    #       prompt_overrides = {}
    #       for override in args.shot_override:
    #           idx_str, prompt = override.split(":", 1)
    #           prompt_overrides[int(idx_str)] = prompt
    #
    #   results = runner.generate(
    #       seq_id=args.seq_id,
    #       mode=args.mode,
    #       prompt_overrides=prompt_overrides,
    #       model_override=args.model,
    #   )
    #
    #   total_cost = sum(r.cost_usd for r in results)
    #   success_count = sum(1 for r in results if r.success)
    #
    #   print(f"\n{args.seq_id}: {success_count}/{len(results)} shots succeeded, ${total_cost:.3f}")
    #   for r in results:
    #       status = "OK" if r.success else "FAIL"
    #       print(f"  {r.shot_id}: {status} — {r.output_path or r.error}")
    #
    #   if success_count > 0:
    #       print(f"\nNext: review output, then:")
    #       print(f"  python tools/client_generate.py approve {args.project} {args.seq_id}")
    raise NotImplementedError(
        "rewire to EpisodeRunner.run_scene + dispatch() — phase-21-22 deferred "
        "(client_sequence_runner removed)"
    )


def cmd_approve(args):
    # TODO(phase-21-22): rewire to scene-status mutation through the
    # take/persistence layer (Beat.select_primary + save_scene).
    #   from tools.client_sequence_runner import ClientSequenceRunner
    #   runner = ClientSequenceRunner(args.project, args.episode)
    #   runner.approve(args.seq_id)
    #   print(f"Sequence {args.seq_id} approved")
    raise NotImplementedError(
        "rewire to Beat.select_primary + persistence.save_scene — "
        "phase-21-22 deferred (client_sequence_runner removed)"
    )


def main():
    parser = argparse.ArgumentParser(
        description="Client video generation workflow",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument(
        "--episode", type=int, default=1,
        help="Episode number (default: 1)",
    )
    parser.add_argument(
        "-v", "--verbose", action="store_true",
        help="Enable debug logging",
    )

    subparsers = parser.add_subparsers(dest="command", required=True)

    # status
    p_status = subparsers.add_parser("status", help="Show sequence status")
    p_status.add_argument("project", help="Project name (e.g., driver-beware)")

    # init
    p_init = subparsers.add_parser("init", help="Initialize sequence state from plan")
    p_init.add_argument("project", help="Project name")

    # grid
    p_grid = subparsers.add_parser("grid", help="Generate start frame grid")
    p_grid.add_argument("project", help="Project name")
    p_grid.add_argument("seq_id", help="Sequence ID (e.g., SEQ01)")
    p_grid.add_argument("--prompt", help="Custom grid prompt (default: auto from plan)")
    p_grid.add_argument("--grid-size", default="2x2", help="Grid layout (default: 2x2)")
    p_grid.add_argument("--model", help="Image model override")

    # pick
    p_pick = subparsers.add_parser("pick", help="Pick a cell from grid as start frame")
    p_pick.add_argument("project", help="Project name")
    p_pick.add_argument("seq_id", help="Sequence ID")
    p_pick.add_argument("--quadrant", required=True,
                        help="Cell to extract: top_left/tl/1, top_right/tr/2, etc.")
    p_pick.add_argument("--grid-size", default="2x2", help="Grid layout (default: 2x2)")

    # generate
    p_gen = subparsers.add_parser("generate", help="Generate video for sequence")
    p_gen.add_argument("project", help="Project name")
    p_gen.add_argument("seq_id", help="Sequence ID")
    p_gen.add_argument("--mode", choices=["multi_shot", "individual"],
                       default="multi_shot", help="Generation mode (default: multi_shot)")
    p_gen.add_argument("--shot-override", action="append",
                       help="Override shot prompt: INDEX:PROMPT (0-based)")
    p_gen.add_argument("--model", help="Model override")

    # approve
    p_approve = subparsers.add_parser("approve", help="Approve sequence output")
    p_approve.add_argument("project", help="Project name")
    p_approve.add_argument("seq_id", help="Sequence ID")

    args = parser.parse_args()

    # Configure logging
    level = logging.DEBUG if args.verbose else logging.INFO
    logging.basicConfig(
        level=level,
        format="%(asctime)s %(name)s %(levelname)s %(message)s",
        datefmt="%H:%M:%S",
    )

    # Dispatch
    commands = {
        "status": cmd_status,
        "init": cmd_init,
        "grid": cmd_grid,
        "pick": cmd_pick,
        "generate": cmd_generate,
        "approve": cmd_approve,
    }
    commands[args.command](args)


if __name__ == "__main__":
    main()
