"""
CLI commands for state management.

This module provides commands for viewing and managing persuade's unified state,
which tracks both sync operations and session continuity.

Commands:
    state show: Display current state (sync and session)
    state clear: Clear session state only
    state clear-all: Clear all state (sync and session)
    state session: Update session state fields
"""

from pathlib import Path

import click

from persuade.state import PersuadeState


@click.group()
def state() -> None:
    """Manage persuade state (sync tracking and session continuity)."""


@state.command("show")
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
@click.option("--path", type=click.Path(exists=True), default=".", help="Project path")
def show(as_json: bool, path: str) -> None:
    """Display current persuade state."""
    import json as json_module

    project_path = Path(path).resolve()
    state_obj = PersuadeState.load(project_path)

    if as_json:
        click.echo(json_module.dumps(state_obj.to_dict(), indent=2))
        return

    # Human-readable output
    click.echo("=== Persuade State ===\n")

    # Sync state
    click.echo("Sync State:")
    if state_obj.sync.synced_files:
        click.echo(f"  Files tracked: {len(state_obj.sync.synced_files)}")
        click.echo(f"  Last sync: {state_obj.sync.last_sync or 'Never'}")
        click.echo(f"  Version: {state_obj.sync.persuade_version or 'Unknown'}")

        external = state_obj.sync.get_external_destinations()
        if external:
            click.echo("\n  External files:")
            for dest in external[:10]:  # Show first 10
                click.echo(f"    - {dest}")
            if len(external) > 10:
                click.echo(f"    ... and {len(external) - 10} more")
    else:
        click.echo("  No files tracked (run 'persuade sync' first)")

    click.echo()

    # Session state
    click.echo("Session State:")
    if state_obj.session.is_valid():
        click.echo(f"  Last updated: {state_obj.session.last_updated}")
        if state_obj.session.working_directory:
            click.echo(f"  Working directory: {state_obj.session.working_directory}")
        if state_obj.session.git_branch:
            click.echo(f"  Git branch: {state_obj.session.git_branch}")
        if state_obj.session.current_task:
            click.echo(f"  Current task: {state_obj.session.current_task}")
        if state_obj.session.learned_patterns:
            click.echo(f"  Learned patterns: {len(state_obj.session.learned_patterns)}")
            for pattern in state_obj.session.learned_patterns[:5]:
                click.echo(f"    - {pattern}")
            if len(state_obj.session.learned_patterns) > 5:
                click.echo(f"    ... and {len(state_obj.session.learned_patterns) - 5} more")
    else:
        click.echo("  No active session (or session expired)")

    click.echo()

    # Metadata
    click.echo("Metadata:")
    click.echo(f"  Schema version: {state_obj.meta.schema_version}")
    click.echo(f"  Created: {state_obj.meta.created_at or 'Unknown'}")
    click.echo(f"  Persuade version: {state_obj.meta.persuade_version or 'Unknown'}")


@state.command("clear")
@click.option("--path", type=click.Path(exists=True), default=".", help="Project path")
@click.confirmation_option(prompt="Clear session state?")
def clear(path: str) -> None:
    """Clear session state only (preserves sync tracking)."""
    project_path = Path(path).resolve()
    state_obj = PersuadeState.load(project_path)

    state_obj.clear_session()

    try:
        state_obj.save(project_path)
    except OSError as e:
        raise click.ClickException(f"Failed to save state: {e}") from e

    click.echo("Session state cleared.")


@state.command("clear-all")
@click.option("--path", type=click.Path(exists=True), default=".", help="Project path")
@click.confirmation_option(prompt="Clear ALL state (sync and session)?")
def clear_all(path: str) -> None:
    """Clear all state (sync and session tracking)."""
    project_path = Path(path).resolve()
    state_obj = PersuadeState.load(project_path)

    state_obj.clear_all()

    try:
        state_obj.save(project_path)
    except OSError as e:
        raise click.ClickException(f"Failed to save state: {e}") from e

    click.echo("All state cleared.")


@state.command("session")
@click.option("--task", help="Set current task description")
@click.option("--branch", help="Set git branch")
@click.option("--pattern", multiple=True, help="Add learned pattern (can repeat)")
@click.option("--cwd", is_flag=True, help="Record current working directory")
@click.option("--path", type=click.Path(exists=True), default=".", help="Project path")
def session(
    task: str | None,
    branch: str | None,
    pattern: tuple[str, ...],
    cwd: bool,
    path: str,
) -> None:
    """Update session state fields."""
    project_path = Path(path).resolve()
    state_obj = PersuadeState.load(project_path)

    updated = False

    # Update fields that were provided
    if task is not None:
        state_obj.session.update(current_task=task)
        click.echo(f"Task set: {task}")
        updated = True

    if branch is not None:
        state_obj.session.update(git_branch=branch)
        click.echo(f"Branch set: {branch}")
        updated = True

    if pattern:
        for p in pattern:
            state_obj.session.add_pattern(p)
            click.echo(f"Pattern added: {p}")
        updated = True

    if cwd:
        state_obj.session.update(working_directory=str(project_path))
        click.echo(f"Working directory set: {project_path}")
        updated = True

    if not updated:
        click.echo("No changes made. Use --help to see available options.")
        return

    try:
        state_obj.save(project_path)
    except OSError as e:
        raise click.ClickException(f"Failed to save state: {e}") from e


def register_state_commands(cli_group: click.Group) -> None:
    """Register state commands with the main CLI group."""
    cli_group.add_command(state)
