"""Using :pypi:`terminaltables` to draw ANSI tables."""
import sys
from operator import itemgetter
from typing import (
    IO,
    Any,
    Callable,
    Iterable,
    List,
    Mapping,
    Optional,
    Sequence,
    Type,
    cast,
)

from mode.utils import logging, text
from mode.utils.compat import isatty
from terminaltables import AsciiTable, SingleTable
from terminaltables.base_table import BaseTable as Table

__all__ = ["Table", "TableDataT", "table", "logtable"]

TableDataT = Sequence[Sequence[str]]


def table(
    data: TableDataT,
    *,
    title: str,
    target: IO = None,
    tty: Optional[bool] = None,
    **kwargs: Any
) -> Table:
    """Create suitable :pypi:`terminaltables` table for target.

    Arguments:
        data (Sequence[Sequence[str]]): Table data.

        target (IO): Target should be the destination output file
                     for your table, and defaults to :data:`sys.stdout`.
                     ANSI codes will be used if the target has a controlling
                     terminal, but not otherwise, which is why it's important
                     to pass the correct output file.
    """
    if target is None:
        target = sys.stdout
    if tty is None:
        tty = isatty(target)
    if tty is None:
        tty = False
    return _get_best_table_type(tty)(data, title=title, **kwargs)


def logtable(
    data: TableDataT,
    *,
    title: str,
    target: IO = None,
    tty: Optional[bool] = None,
    headers: Optional[Sequence[str]] = None,
    **kwargs: Any
) -> str:
    """Prepare table for logging.

    Will use ANSI escape codes if the log file is a tty.
    """
    if tty is None:
        tty = logging.LOG_ISATTY
    if headers:
        data = [headers] + list(data)
    return table(data, title=title, target=target, tty=tty, **kwargs).table


def _get_best_table_type(tty: bool) -> Type[Table]:
    return SingleTable if tty else AsciiTable


DEFAULT_SORT_KEY = itemgetter(0)


def dict_as_ansitable(
    d: Mapping,
    *,
    key: str = "Key",
    value: str = "Value",
    sort: bool = False,
    sortkey: Callable[[Any], Any] = DEFAULT_SORT_KEY,
    target: IO = sys.stdout,
    title: Optional[str] = None
) -> str:
    header = [text.title(key), text.title(value)]
    data = cast(Iterable[List[str]], d.items())
    data = sorted(data, key=sortkey) if sort else list(data)
    if sort:
        data = sorted(data, key=sortkey)
    return table(
        [header] + list(data),
        title=text.title(title) if title is not None else "",
        target=target,
    ).table
