from typing import Tuple

import logging
from pathlib import Path

from .struct import Struct
from .enum import Enum
from .build import build_structs
from .format import format_code
from .jinja_env import env

log = logging.getLogger(__name__)


def _generate_implementation(header_path: str, items: list[Struct | Enum]) -> str:
    current_ns = ""
    doc = f"""// WARNING: This file is automatically generated. Any changes will be lost.
#include "{header_path}"
#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep
#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep
#include "twitch-eventsub-ws/detail/errors.hpp"
#include <boost/json.hpp>

"""

    for item in items:
        next_ns = "::".join(item.namespace)
        if next_ns != current_ns:
            if current_ns:
                doc += "} // namespace " + current_ns + "\n"
            if next_ns:
                doc += "namespace " + next_ns + "{\n\n"
            current_ns = next_ns
        doc += item.try_value_to_implementation(env) + "\n\n"

    if current_ns:
        doc += "\n} // namespace " + current_ns + "\n\n"

    return doc


def _get_relative_header_path(header_path: str) -> str:
    root_path = Path(__file__).parent.parent.parent / "include"
    return Path(header_path).relative_to(root_path).as_posix()


def generate(header_path: str, source_path: str, additional_includes: list[str] = []) -> Tuple[str, str]:
    structs = build_structs(header_path, additional_includes)

    rel_header_path = _get_relative_header_path(header_path)

    log.debug("Generate & format definitions")
    # Technically the definitions we save will be saved in an .inc file, but for the purpose of formatting the code we can assume it's the real header file
    definitions = format_code(header_path, "\n\n".join([struct.try_value_to_definition(env) for struct in structs]))

    log.debug("Generate & format implementations")
    implementations = format_code(source_path, _generate_implementation(rel_header_path, structs))

    return (definitions, implementations)
