import itertools as it
import operator
import typing as t
from pathlib import Path

import black
from isort.api import sort_file

from .domain import CodeBlock
from .domain import Import


def write(root: Path, name: str, codeblocks: t.Iterator[CodeBlock]) -> None:
    file_name = root / f"{name}.py"
    with open(root / f"{name}.py", "w") as f:
        f.writelines(it.chain(*zip(generate_lines(name, codeblocks), it.cycle("\n"))))
    reformat_file(file_name)


def generate_lines(name: str, codeblocks: t.Iterator[CodeBlock]) -> t.Iterator[str]:
    yield "# generated by pasiphae, please do not change manually"
    module = f".{name}"
    codeblocks, for_imports = it.tee(codeblocks, 2)

    all_types = it.chain(*map(operator.attrgetter("used_types"), for_imports))

    def check(import_: Import) -> bool:
        return import_.module != module

    yield from map(
        str, filter(check, it.chain(*map(operator.methodcaller("imports"), all_types)))
    )

    yield ""
    for definition in sorted(codeblocks, key=operator.attrgetter("weight")):
        if definition:
            yield definition.body
            yield ""


def reformat_file(path: Path) -> None:
    black.reformat_one(
        src=path,
        fast=False,
        write_back=black.WriteBack.YES,
        mode=black.Mode(),
        report=black.Report(quiet=True),
    )
    sort_file(path, quiet=True)
