import os.path
import pathlib
import zipfile
import os
import sys

import logging
import logging.config

logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        }
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'standard',
            'stream': 'ext://sys.stderr',
        },
    },
    'loggers': {
        '': {  # root logger
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': True
        },
    }
})

logger = logging.getLogger()

def extract(zip_path: str, dest: str, skip_checks: bool = False):
    """
    Did you know that `.r2z` is just a badly compressed zip?

    Utilized to automate version controlling configs and plugin manifests

    NB: Do not use this to install profiles. Most mod manager has an install step
    after extracting.

    `dest` needs to be profiled path, that is, should be something like 
    `//profiles/my-profile`, not just `//profiles` with `zip_path` 
    `//exports/my-profile`
    """
    p = pathlib.Path(zip_path)
    to_dir = pathlib.Path(dest)
    if to_dir.is_file():
        raise KeyError("Expected dest to be directory or be recursively made")

    if not p.suffix.lower() == ".r2z" and not skip_checks:
        raise KeyError("Expected r2z suffix, use `skip_checks` to bypass")

    profile_dir = to_dir
    os.makedirs(profile_dir, exist_ok=True)

    with zipfile.ZipFile(p, 'r') as zip_ref:
        logging.info(f"Extracting {p} to {profile_dir}")
        zip_ref.extractall(profile_dir)

def repo_root_impure():
    cwd = pathlib.Path.cwd()
    return cwd.parent if cwd.name == "script" else cwd

def main():
    dry_run = os.getenv("DRY_RUN", "false").lower() not in ("false", "0", "no", "nope")
    if dry_run: logger.debug("Doing dry run")

    ror2_f = "RiskOfRain2"
    MODMAN_PATH_ENV = "ROR2_MODMAN_PATH"
    MODMAN_CANDIDATES = [
        pathlib.Path.home().joinpath("AppData","Roaming", *modman_segs, ror2_f)
        for modman_segs in (("r2modmanPlus-local",), ("Thunderstore Mod Manager", "DataFolder"))
    ]
    mod_man_roots = [pathlib.Path(f) for f in os.getenv(MODMAN_PATH_ENV, "").split(',') if f] or MODMAN_CANDIDATES
    mod_man_roots = [e for e in mod_man_roots if e.is_dir()]
    logging.debug(f"Using {mod_man_roots=}")

    dest_base_loc = pathlib.Path(os.getenv("DEST_BASE_LOC") or repo_root_impure().joinpath("r2_profiles"))
    if dest_base_loc.is_file():
        raise KeyError("{dest_base_loc=} is a file, expected directory or able to recursively make dirs")
    if not dry_run:
        os.makedirs(dest_base_loc, exist_ok=True)
    logging.debug(f"Using {dest_base_loc=}")

    if mod_man_roots == []:
        raise KeyError(f'No mod manager found locally, set "{MODMAN_PATH_ENV}" env or check {MODMAN_CANDIDATES}')

    def profile_of(r2z_fname: pathlib.Path):
        stem = r2z_fname.stem
        v = stem.split("_")
        if len(v) == 1:
            return stem
        *head, tail = v
        if tail.isnumeric():
            return "_".join(head)
        return stem
    # latest profiles (based on OS's reported mtime, disregard r2modman's stem)
    raw_profiles =  [
        file
        for file in sorted(
            # flatten from both roots
            [f for root in mod_man_roots for f in root.joinpath("exports").iterdir()],
            key=lambda e: e.stat().st_mtime, 
            # dict comprehension chooses latter entry if duplicate key
            reverse=False,
        )
        if file.is_file() and file.suffix.lower() == ".r2z"
    ]
    profiles = { profile_of(file): file for file in raw_profiles }
    logger.debug(f"{profiles=}")
    if not dry_run:
        for prof, r2z in profiles.items():
            extract(r2z, dest_base_loc.joinpath(prof))
    logger.info(f"done extracting {len(profiles)} profiles")

if __name__ == "__main__":
    main()
