import logging
import os
import sys
from pathlib import Path
from typing import Union

import typer
from rich.console import Console
from rich.logging import RichHandler

from tilemapper import battlemap
from tilemapper import tileset as _tileset

app = typer.Typer()
app_state = {}

INSTALL_DIR = Path(__file__).parent.parent


@app.callback(invoke_without_command=True)
def main(
    ctx: typer.Context,
    config_dir: Path = typer.Option(default=INSTALL_DIR / "tilesets", help="The path containing tile sets to load."),
    verbose: bool = typer.Option(default=False, help="If True, increase verbosity of status messages."),
):
    app_state["tileset_manager"] = _tileset.TileSetManager(config_dir)
    app_state["config_dir"] = config_dir
    app_state["verbose"] = verbose
    debug = os.getenv("DEBUG", None)
    logging.basicConfig(
        format="%(name)s %(message)s",
        level=logging.DEBUG if debug else logging.INFO,
        handlers=[RichHandler(rich_tracebacks=True, tracebacks_suppress=[typer])],
    )
    if ctx.invoked_subcommand is None:
        render_map()


@app.command()
def list():
    """
    List available tile sets.
    """
    manager = app_state["tileset_manager"]
    print("\n".join(manager.available))


@app.command()
def render(
    source: Path = typer.Option(
        help="The battle map text file to load.", default=INSTALL_DIR / "examples" / "five_room_dungeon.txt"
    ),
    outfile: Path = typer.Option(help="The file to create. If not specified, print to STDOUT", default=None),
    tileset: str = typer.Option(
        help="The name of the tile set to use (run mapper list to see what's available).", default="colorized"
    ),
):
    """
    Create a rendered battle map using a tile set. Will generate a PNG file if the tile set supports it,
    otherwise text output.
    """
    render_map(source, outfile, tileset)


def render_map(
    source: Path = INSTALL_DIR / "examples" / "five_room_dungeon.txt",
    outfile: Union[Path, None] = None,
    tileset: str = 'colorized'
):
    manager = app_state["tileset_manager"]
    if tileset not in manager.available:
        raise RuntimeError(f"Could not locate the tile set {tileset} in {manager.config_dir}.")

    try:
        bmap = battlemap.BattleMap(name=source.name, source=source, tileset=manager.load(tileset))
        bmap.load()
    except battlemap.UnsupportedTileException as e:
        logging.error(e)
        sys.exit(1)

    try:
        image = bmap.as_image()
        if outfile:
            image.save(outfile)
            outfile.write_text(bmap.render())
            print(f"Wrote {outfile.stat().st_size} bytes to {outfile}")
        else:
            image.save(sys.stdout, "png")
        return
    except NotImplementedError:
        pass
    console = Console()
    console.print(repr(bmap), highlight=False)


if __name__ == "__main__":
    app()
