#!/usr/bin/env python3
import argparse
import getpass
import shutil
import subprocess as sp
from pathlib import Path

import jinja2

bitwarden_session = None


def _add_args(parser: argparse.ArgumentParser):
    parser.add_argument(
        "search_paths",
        help="start directory to walk files to find secret references",
        default=".",
        nargs="*",
    )
    parser.add_argument(
        "--bw-path", "-b",
        help="custom path for bitwarden cli executable",
        default=shutil.which("bw"),
    )


def init_bw_session(bw_path: Path):
    global bitwarden_session

    if (pw_file := Path("./.bw2secrets")).exists():
        bitwarden_password = pw_file.read_text().strip()
    else:
        print("Please, provide your bitwarden master password")
        bitwarden_password = getpass.getpass("Master password: ")
    res = sp.run(
        [bw_path, "unlock", bitwarden_password, "--raw"], capture_output=True,
        text=True,
    )
    res.check_returncode()
    bitwarden_session = res.stdout


def sync_bw_session(bw_path: Path):
    global bitwarden_session
    res = sp.run(
        [bw_path, "sync", "--session", bitwarden_session], capture_output=True,
        text=True,
    )
    res.check_returncode()


def find_templates(base_dirs: set[Path]) -> set[Path]:
    env_templates: set[Path] = set()
    for path in base_dirs:
        for env_template in path.glob(f"{path}/**/*.template"):
            env_templates.add(env_template)
    return env_templates


def fetch_secret(bw_path: Path, secret_id: str) -> str:
    global bitwarden_session
    res = sp.run(
        [bw_path, "get", "password", secret_id, "--session", bitwarden_session],
        capture_output=True,
        text=True,
    )
    res.check_returncode()
    return res.stdout


def secret_filter(bw_path: Path, secret_id: str) -> str:
    return fetch_secret(bw_path, secret_id)


def compile_file(file_path: Path, bw_path: Path):
    jinja_env = jinja2.Environment(
        loader=jinja2.FileSystemLoader(file_path.parent),
    )
    jinja_env.filters['secret'] = lambda secret_id: secret_filter(
        bw_path, secret_id,
    )

    template = jinja_env.get_template(file_path.name)

    rendered_template = template.render()
    file_path.with_name(
        file_path.name.replace(
            ".template", "",
        ),
    ).write_text(rendered_template)


def main() -> int:
    parser = argparse.ArgumentParser("bw2secrets")
    _add_args(parser)
    args = parser.parse_args()

    if not (bw_path := args.bw_path):
        print("Bitwarden CLI `bw` executable not found in PATH")
        return 1

    search_paths: set[Path | None] = set()
    for path in args.search_paths:
        search_path = Path(path)
        search_paths.add(search_path)

    template_files = find_templates(search_paths)

    init_bw_session(bw_path)

    for file in template_files:
        compile_file(file, bw_path)

    return 0


if __name__ == "__main__":
    raise SystemExit(main())