"""CLI for license management.

Four commands:

- ``activate BLOB --name NAME --email EMAIL``
    First-time activation. Verifies the signed blob, ensures the
    name + email match, writes ``~/.datatools/license.json``.

- ``renew BLOB``
    Apply a renewal blob to the currently-active license. The blob's
    embedded name + email must match the active license; tier may
    differ (upgrade path, e.g., Lite → Core).

- ``status [--json]``
    Print the current license state. Human-readable by default;
    ``--json`` emits the same payload as a JSON document for piping
    into shell scripts / monitoring.

- ``deactivate``
    Remove the local license file.

This CLI is exempt from the guard that protects every tool CLI —
otherwise a user with no license couldn't run ``activate``.

There is **no free-trial subcommand**: every license requires a paid
blob from the seller. The internal ``LicenseManager._mint`` API is
used by tests and by the seller's ``scripts/generate_license.py``;
end users have no way to self-issue a license.
"""

from __future__ import annotations

import json
import sys
from typing import Optional

import typer

from src.license import (
    LicenseError,
    Tier,
    get_manager,
)
from src.license.manager import LicenseManager


app = typer.Typer(
    name="license",
    help=(
        "Manage your DataTools license: activate a paid blob, renew, "
        "check status, or self-issue a 1-year trial.\n\n"
        "All operations are local — no internet calls. The signed "
        "license file lives at ~/.datatools/license.json (override "
        "with $DATATOOLS_LICENSE_PATH)."
    ),
    add_completion=False,
    no_args_is_help=True,
)


@app.command()
def activate(
    blob: str = typer.Argument(..., help="License blob from the delivery email (starts with DTLIC1:)."),
    name: str = typer.Option(..., "--name", "-n", help="Buyer name (must match the blob)."),
    email: str = typer.Option(..., "--email", "-e", help="Buyer email (must match the blob)."),
) -> None:
    """Verify and install a license blob."""
    mgr = get_manager()
    try:
        lic = mgr.activate_from_blob(blob, name=name, email=email)
    except LicenseError as e:
        typer.echo(f"Activation failed: {e}", err=True)
        raise typer.Exit(code=2)
    typer.echo(
        f"Activated. Tier: {lic.tier.value} · "
        f"Key: {lic.license_key} · "
        f"Expires: {lic.expires_at[:10]}"
    )


@app.command()
def renew(
    blob: str = typer.Argument(..., help="Renewal blob from the renewal email."),
) -> None:
    """Apply a renewal blob to the currently active license."""
    mgr = get_manager()
    try:
        lic = mgr.renew(blob)
    except LicenseError as e:
        typer.echo(f"Renewal failed: {e}", err=True)
        raise typer.Exit(code=2)
    typer.echo(
        f"Renewed. New expiry: {lic.expires_at[:10]} "
        f"({lic.days_remaining()} days)"
    )


@app.command()
def status(
    json_output: bool = typer.Option(False, "--json", help="Emit JSON instead of human-readable text."),
) -> None:
    """Print the current license state."""
    state = get_manager().current_state()
    if json_output:
        typer.echo(json.dumps(state.as_dict(), indent=2))
        return

    if not state.activated:
        typer.echo("Status: not activated.")
        typer.echo(
            "Run: python -m src.license_cli activate <blob> "
            "--name 'Your Name' --email you@example.com"
        )
        raise typer.Exit(code=1)
    if state.error_kind == "invalid":
        typer.echo(f"Status: invalid. {state.error_message}")
        raise typer.Exit(code=2)
    if state.error_kind == "expired":
        typer.echo(
            f"Status: expired on {state.expires_at[:10]}. "
            f"Renew with: python -m src.license_cli renew <blob>"
        )
        raise typer.Exit(code=2)

    typer.echo(
        f"Status: active.\n"
        f"  Name:     {state.name}\n"
        f"  Email:    {state.email}\n"
        f"  Tier:     {state.tier}\n"
        f"  Key:      {state.license_key}\n"
        f"  Issued:   {state.issued_at[:10]}\n"
        f"  Expires:  {state.expires_at[:10]} ({state.days_remaining} days)\n"
        f"  Features: {', '.join(state.features)}"
    )


@app.command()
def deactivate(
    confirm: bool = typer.Option(
        False, "--yes", "-y", help="Skip the interactive confirmation.",
    ),
) -> None:
    """Remove the local license file (does NOT contact a server)."""
    if not confirm:
        if not typer.confirm(
            "This removes the license file at ~/.datatools/license.json. Continue?",
            default=False,
        ):
            typer.echo("Aborted.")
            raise typer.Exit(code=1)
    removed = get_manager().deactivate()
    if removed:
        typer.echo("Deactivated. The license file has been removed.")
    else:
        typer.echo("No license was active; nothing to deactivate.")


def main() -> None:
    app()


if __name__ == "__main__":
    main()
