#!/usr/bin/env python
import os
from rich.console import Console
from rich.table import Table
from rich import box
import re
import dotenv
from utils.console import handle_input

console = Console()


def check_env() -> bool:
    if not os.path.exists(".env.template"):
        console.print("[red]Couldn't find .env.template. Unable to check variables.")
        return True
    if not os.path.exists(".env"):
        console.print("[red]Couldn't find the .env file, creating one now.")
        with open(".env", "x") as file:
            file.write("")
    success = True
    with open(".env.template", "r") as template:
        # req_envs = [env.split("=")[0] for env in template.readlines() if "=" in env]
        matching = {}
        explanations = {}
        bounds = {}
        types = {}
        oob_errors = {}
        examples = {}
        req_envs = []
        var_optional = False
        for line in template.readlines():
            if line.startswith("#") is not True and "=" in line and var_optional is not True:
                req_envs.append(line.split("=")[0])
                if "#" in line:
                    examples[line.split("=")[0]] = "#".join(line.split("#")[1:]).strip()
            elif "#OPTIONAL" in line:
                var_optional = True
            elif line.startswith("#MATCH_REGEX "):
                matching[req_envs[-1]] = line.removeprefix("#MATCH_REGEX ")[:-1]
                var_optional = False
            elif line.startswith("#OOB_ERROR "):
                oob_errors[req_envs[-1]] = line.removeprefix("#OOB_ERROR ")[:-1]
                var_optional = False
            elif line.startswith("#RANGE "):
                bounds[req_envs[-1]] = tuple(
                    map(
                        lambda x: float(x) if x != "None" else None,
                        line.removeprefix("#RANGE ")[:-1].split(":"),
                    )
                )
                var_optional = False
            elif line.startswith("#MATCH_TYPE "):
                types[req_envs[-1]] = eval(line.removeprefix("#MATCH_TYPE ")[:-1].split()[0])
                var_optional = False
            elif line.startswith("#EXPLANATION "):
                explanations[req_envs[-1]] = line.removeprefix("#EXPLANATION ")[:-1]
                var_optional = False
            else:
                var_optional = False
    missing = set()
    incorrect = set()
    dotenv.load_dotenv()
    for env in req_envs:
        value = os.getenv(env)
        if value is None:
            missing.add(env)
            continue
        if env in matching.keys():
            re.match(matching[env], value) is None and incorrect.add(env)
        if env in bounds.keys() and env not in types.keys():
            len(value) >= bounds[env][0] or (
                len(bounds[env]) > 1 and bounds[env][1] >= len(value)
            ) or incorrect.add(env)
            continue
        if env in types.keys():
            try:
                temp = types[env](value)
                if env in bounds.keys():
                    (bounds[env][0] <= temp or incorrect.add(env)) and len(bounds[env]) > 1 and (
                        bounds[env][1] >= temp or incorrect.add(env)
                    )
            except ValueError:
                incorrect.add(env)

    if len(missing):
        table = Table(
            title="Missing variables",
            highlight=True,
            show_lines=True,
            box=box.ROUNDED,
            border_style="#414868",
            header_style="#C0CAF5 bold",
            title_justify="left",
            title_style="#C0CAF5 bold",
        )
        table.add_column("Variable", justify="left", style="#7AA2F7 bold", no_wrap=True)
        table.add_column("Explanation", justify="left", style="#BB9AF7", no_wrap=False)
        table.add_column("Example", justify="center", style="#F7768E", no_wrap=True)
        table.add_column("Min", justify="right", style="#F7768E", no_wrap=True)
        table.add_column("Max", justify="left", style="#F7768E", no_wrap=True)
        for env in missing:
            table.add_row(
                env,
                explanations[env] if env in explanations.keys() else "No explanation given",
                examples[env] if env in examples.keys() else "",
                str(bounds[env][0]) if env in bounds.keys() and bounds[env][1] is not None else "",
                str(bounds[env][1])
                if env in bounds.keys() and len(bounds[env]) > 1 and bounds[env][1] is not None
                else "",
            )
        console.print(table)
        success = False
    if len(incorrect):
        table = Table(
            title="Incorrect variables",
            highlight=True,
            show_lines=True,
            box=box.ROUNDED,
            border_style="#414868",
            header_style="#C0CAF5 bold",
            title_justify="left",
            title_style="#C0CAF5 bold",
        )
        table.add_column("Variable", justify="left", style="#7AA2F7 bold", no_wrap=True)
        table.add_column("Current value", justify="left", style="#F7768E", no_wrap=False)
        table.add_column("Explanation", justify="left", style="#BB9AF7", no_wrap=False)
        table.add_column("Example", justify="center", style="#F7768E", no_wrap=True)
        table.add_column("Min", justify="right", style="#F7768E", no_wrap=True)
        table.add_column("Max", justify="left", style="#F7768E", no_wrap=True)
        for env in incorrect:
            table.add_row(
                env,
                os.getenv(env),
                explanations[env] if env in explanations.keys() else "No explanation given",
                str(types[env].__name__) if env in types.keys() else "str",
                str(bounds[env][0]) if env in bounds.keys() else "None",
                str(bounds[env][1]) if env in bounds.keys() and len(bounds[env]) > 1 else "None",
            )
            missing.add(env)
        console.print(table)
        success = False
    if success is True:
        return True
    console.print(
        "[green]Do you want to automatically overwrite incorrect variables and add the missing variables? (y/n)"
    )
    if not input().casefold().startswith("y"):
        console.print("[red]Aborting: Unresolved missing variables")
        return False
    if len(incorrect):
        with open(".env", "r+") as env_file:
            lines = []
            for line in env_file.readlines():
                line.split("=")[0].strip() not in incorrect and lines.append(line)
            env_file.seek(0)
            env_file.write("\n".join(lines))
            env_file.truncate()
        console.print("[green]Successfully removed incorrectly set variables from .env")
    with open(".env", "a") as env_file:
        for env in missing:
            env_file.write(
                env
                + "="
                + ('"' if env not in types.keys() else "")
                + str(
                    handle_input(
                        "[#F7768E bold]" + env + "[#C0CAF5 bold]=",
                        types[env] if env in types.keys() else False,
                        matching[env] if env in matching.keys() else ".*",
                        explanations[env]
                        if env in explanations.keys()
                        else "Incorrect input. Try again.",
                        bounds[env][0] if env in bounds.keys() else None,
                        bounds[env][1] if env in bounds.keys() and len(bounds[env]) > 1 else None,
                        oob_errors[env] if env in oob_errors.keys() else "Input too long/short.",
                        extra_info="[#C0CAF5 bold]⮶ "
                        + (
                            explanations[env] if env in explanations.keys() else "No info available"
                        ),
                    )
                )
                + ('"' if env not in types.keys() else "")
                + "\n"
            )
    return True


if __name__ == "__main__":
    check_env()