from __future__ import annotations

from datetime import datetime, timezone
from pathlib import Path

import click
import jwt

from sitedrop.client.api import SitedropClient, SitedropError
from sitedrop.client.config import ClientConfig


def _get_client() -> SitedropClient:
    config = ClientConfig.load()
    if not config.server_url:
        click.echo("Error: not logged in. Run 'sitedrop login' first.", err=True)
        raise SystemExit(1)
    return SitedropClient(config)


@click.command()
@click.option(
    "--url", prompt="Server URL", default="http://localhost:8000", help="Server URL"
)
@click.option("--password", prompt=True, hide_input=True, help="Admin password")
def login(url: str, password: str):
    """Log in to a sitedrop server."""
    config = ClientConfig()
    client = SitedropClient(config)
    try:
        client.login(url, password)
        click.echo(f"Logged in to {url}")
    except Exception as e:
        click.echo(f"Login failed: {e}", err=True)
        raise SystemExit(1)


@click.command()
@click.argument("file", type=click.Path(exists=True, path_type=Path))
@click.option("--name", default=None, help="Site name (defaults to filename stem)")
@click.option("--force", is_flag=True, help="Overwrite existing site without prompting")
def upload(file: Path, name: str | None, force: bool):
    """Upload an HTML file as a site."""
    if name is None:
        name = file.stem

    content = file.read_text(encoding="utf-8")
    client = _get_client()

    try:
        info = client.upload(name, content, force=force)
        server_url = client.base_url
        click.echo(f"Uploaded: {server_url}/{info['name']} ({info['size']} bytes)")
    except SitedropError as e:
        if "already exists" in str(e) and not force:
            if click.confirm(f"Site '{name}' already exists. Overwrite?"):
                try:
                    info = client.upload(name, content, force=True)
                    server_url = client.base_url
                    click.echo(
                        f"Uploaded: {server_url}/{info['name']} ({info['size']} bytes)"
                    )
                except Exception as e2:
                    click.echo(f"Upload failed: {e2}", err=True)
                    raise SystemExit(1)
            else:
                click.echo("Aborted.")
        else:
            click.echo(f"Upload failed: {e}", err=True)
            raise SystemExit(1)
    except Exception as e:
        click.echo(f"Upload failed: {e}", err=True)
        raise SystemExit(1)


@click.command("list")
def list_sites():
    """List all hosted sites."""
    client = _get_client()
    try:
        sites = client.list_sites()
    except Exception as e:
        click.echo(f"Failed: {e}", err=True)
        raise SystemExit(1)

    if not sites:
        click.echo("No sites.")
        return

    name_width = max(len("Name"), max(len(s["name"]) for s in sites))
    size_width = max(len("Size"), max(len(str(s["size"])) for s in sites))
    click.echo(f"{'Name':<{name_width}}  {'Size':>{size_width}}  {'Modified'}")
    click.echo("-" * (name_width + size_width + 24))
    for s in sites:
        click.echo(
            f"{s['name']:<{name_width}}  {s['size']:>{size_width}}  {s['modified']}"
        )


@click.command()
@click.argument("name")
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
def delete(name: str, yes: bool):
    """Delete a hosted site."""
    if not yes:
        if not click.confirm(f"Delete site '{name}'?"):
            click.echo("Aborted.")
            return
    client = _get_client()
    try:
        msg = client.delete(name)
        click.echo(msg)
    except Exception as e:
        click.echo(f"Delete failed: {e}", err=True)
        raise SystemExit(1)


@click.command()
def password():
    """Change the server password."""
    current = click.prompt("Current password", hide_input=True)
    new = click.prompt("New password", hide_input=True, confirmation_prompt=True)
    client = _get_client()
    try:
        result = client.change_password(current, new)
        client.config.password = new
        client.config.save()
        click.echo(result["message"])
    except Exception as e:
        click.echo(f"Password change failed: {e}", err=True)
        raise SystemExit(1)


@click.command()
def info():
    """Show connection info and token status."""
    config = ClientConfig.load()
    if not config.server_url:
        click.echo("Not logged in. Run 'sitedrop login' first.")
        return

    click.echo(f"Server: {config.server_url}")

    if not config.token:
        click.echo("Token: none")
        return

    try:
        payload = jwt.decode(config.token, options={"verify_signature": False})
        exp = datetime.fromtimestamp(payload["exp"], tz=timezone.utc)
        now = datetime.now(timezone.utc)
        if exp < now:
            click.echo(f"Token: expired at {exp.strftime('%Y-%m-%d %H:%M:%S UTC')}")
        else:
            remaining = exp - now
            hours, remainder = divmod(int(remaining.total_seconds()), 3600)
            minutes = remainder // 60
            click.echo(
                f"Token: valid until {exp.strftime('%Y-%m-%d %H:%M:%S UTC')} ({hours}h {minutes}m remaining)"
            )
    except (jwt.PyJWTError, KeyError):
        click.echo("Token: invalid")
