import sys
import os
import re
from shutil import rmtree

from .parameters import PACK_VERSION

TFD = "text-fabric-data"
GH = "github"

ROOTS = [TFD, GH]

binRe = re.compile(r"/\.tf$")
binvRe = re.compile(r"/\.tf/([^/]+)$")


def out(msg):
    """Write to standard normal output immediately."""
    sys.stdout.write(msg)
    sys.stdout.flush()


def err(msg):
    """Write to standard error output immediately."""
    sys.stderr.write(msg)
    sys.stderr.flush()


def clean(tfd=True, gh=False, dry=True, specific=None, current=False):
    """Clean up older compressed .tfx files.

    Parameters
    ----------

    Removes all precomputed data resulting from other `PACK_VERSION`s
    than the one currently used by Text-Fabric.

    You find the current pack version in
    `tf.parameters`

    tfd: boolean,  optional `True`
        By default, your `~/text-fabric-data` is traversed and cleaned,
        but if you pass `tfd=False` it will be skipped.
    gh: boolean, optional, `False`
        By default, your `~/github` will be skipped,
        but if you pass `gh=True` it will be
        traversed and cleaned.
    specific: string, optional, `None`
        You can pass a specific directory here. The standard directories
        `~/github` and `~/text-fabric-data` will not be used, only
        the directory you pass here. `~` will be expanded to your home directory.
    current: boolean, optional, `False`
        If current=True, also the precomputed results of the current version will
        be removed.
    dry: boolean, optional, `False`
        By default, nothing will be deleted, and you only get a list of
        what will be deleted if it were not a dry run.
        If you pass `dry=False` the delete actions will really be executed.
    """

    if specific is not None:
        bases = [os.path.expanduser(specific)]
    else:
        for root in ROOTS:
            if root == TFD and not tfd or root == GH and not gh:
                sys.stdout.write(f"skipped {root}\n")
                continue
            bases.append(os.path.expanduser(f"~/{root}"))

    for base in bases:
        for triple in os.walk(base):
            d = triple[0]
            if binRe.search(d):
                files = triple[2]
                if files:
                    err(f"{d} legacy: delete {len(files)} files ... ")
                    if dry:
                        err("dry\n")
                    else:
                        for f in files:
                            os.unlink(f"{d}/{f}")
                        err("done\n")
                    continue
            match = binvRe.search(d)
            if match:
                binv = match.group(1)
                if not current and binv == PACK_VERSION:
                    out(f"{d} version {binv}: keep\n")
                else:
                    files = triple[2]
                    err(f"{d} version {binv}: delete it and its {len(files)} files ...")
                    if dry:
                        err("dry\n")
                    else:
                        rmtree(d)
                        err("done\n")
    if dry:
        sys.stdout.write("\n")
        sys.stderr.write("This was a dry run\n")
        sys.stderr.write("Say clean(dry=False) to perform the cleaning\n")
