import triplayacc as yacc
import triplalex as lex
import syntax

from pathlib import Path
from graphviz import Source

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import lib.console as cnsl
import os

import matplotlib
matplotlib.use("TkAgg")

# Renders a diagram of the AST
def render_diagram(dot_string: str):
    # Set DPI for PNG
    os.environ["GV_FILE_DPI"] = "300"

    src = Source(dot_string, format="png", engine="dot")
    png_path = src.render(cleanup=True)

    img = mpimg.imread(png_path)

    fig = plt.figure(figsize=(12, 12))
    fig.canvas.manager.window.wm_title("TRIPLA AST Viewer")

    plt.imshow(img)
    plt.axis("off")
    plt.show()

# Pretty prints the AST
def pretty_print(node, indent=0):
    prefix = " " * indent
    print(f"{prefix}{type(node).__name__}:")

    for key, value in node.__dict__.items():
        if isinstance(value, syntax.EXPRESSION):
            pretty_print(value, indent + 4)

        elif isinstance(value, list):
            print(f"{prefix}  {key}: [")
            for element in value:
                if isinstance(element, syntax.EXPRESSION):
                    pretty_print(element, indent + 4)
                else:
                    print(" " * (indent + 4) + str(element))
            print(f"{prefix}  ]")

        else:
            print(f"{prefix}  {key}: {value}")

# Exports the AST as a DOT file
def export_dot_file(dot_string: str, filename: str):
    try:
        Path(filename).write_text(dot_string, encoding="utf-8")
        print(f"Saved DOT file as: {filename}")
    except Exception as e:
        print(f"Could not save DOT file: {e}")

if __name__ == "__main__":
    print("\nTRIPLA Parser Tool")

    while True:
        choice = cnsl.prompt_choice("\nSelect action:", ["Parse .tripla", "Exit"])

        if choice == 1:
            print("\nBye Bye.")
            break

        programs = cnsl.search_programs()
        if not programs:
            print("\nNo .tripla files found.")
            continue

        idx = cnsl.prompt_choice("\nSelect program to parse:", [p.name for p in programs])
        path = programs[idx]

        source = path.read_text()
        ast = yacc.parser.parse(source)

        # Pretty print
        if cnsl.prompt_confirmation("\nPretty-print AST?"):
            print("")
            pretty_print(ast)

        # Export DOT
        dot_str = ast.to_dot()
        if cnsl.prompt_confirmation("Export AST as .dot file?"):
            default = f"{path.stem}.dot"
            cnsl = input(f"Filename [{default}]: ").strip()
            if not cnsl:
                cnsl = default
            export_dot_file(dot_str, cnsl)

        # Display AST diagram
        if cnsl.prompt_confirmation("Display AST diagram?"):
            render_diagram(dot_str)
            print("Rendered AST diagram.")
