import os
import sys
from os.path import exists
from subprocess import PIPE, Popen
from typing import List

from sila2.code_generator.template_environment import TemplateEnvironment


class CodeGeneratorBase:
    overwrite: bool
    template_env: TemplateEnvironment
    generated_files: List[str]

    def __init__(self, overwrite: bool = False) -> None:
        self.overwrite = overwrite
        self.template_env = TemplateEnvironment()
        self.generated_files = []

    def generate_file(self, out_filename: str, content: str, *, allow_overwrite: bool = False) -> None:
        if exists(out_filename) and open(out_filename).read() != content and not (self.overwrite or allow_overwrite):
            raise FileExistsError(f"File '{out_filename}' already exists. Set --overwrite to overwrite existing files.")
        with open(out_filename, "w") as fp:
            fp.write(content)

        self.generated_files.append(out_filename)

    def format_generated_files(self) -> None:
        files = [file for file in self.generated_files if file.endswith((".py", ".pyi"))]
        proc_kwargs = dict(encoding="UTF-8", stdout=PIPE, stderr=PIPE)

        isort_proc = Popen(
            [sys.executable] + "-m isort --line-length 120 --quiet --profile black".split() + files,
            **proc_kwargs,
        )
        if isort_proc.wait() != 0:
            raise RuntimeError(f"Failed to run isort: {isort_proc.stderr.read()}")

        black_proc = Popen(
            [sys.executable] + "-m black --line-length 120 --quiet --fast".split() + files, **proc_kwargs
        )
        if black_proc.wait() != 0:
            raise RuntimeError(f"Failed to run black: {black_proc.stderr.read()}")

    def generate_directory(self, dir_: str, *, allow_overwrite: bool = False) -> None:
        if exists(dir_) and os.listdir(dir_) and not (self.overwrite or allow_overwrite):
            raise FileExistsError(f"Directory '{dir_}' already exists. Set --overwrite to overwrite existing files.")
        os.makedirs(dir_, exist_ok=True)
