# ToUpload/generators/generate_scl_code_block.py
# -*- coding: utf-8 -*-
import re
import os  # Importar os
from .generator_utils import format_variable_name, generate_scl_declarations

SCL_SUFFIX = "_sympy_processed"


def _generate_scl_header(data, scl_block_name):
    scl_output = []
    block_type = data.get("block_type", "Unknown")
    block_name = data.get("block_name", "UnknownBlock")
    block_number = data.get("block_number")
    block_comment = data.get("block_comment", "")
    scl_block_keyword = "FUNCTION_BLOCK"
    if block_type == "FC":
        scl_block_keyword = "FUNCTION"
    elif block_type == "OB":
        scl_block_keyword = "ORGANIZATION_BLOCK"

    # Agregar línea de identificación del bloque al inicio
    if block_number and block_type:
        if block_type == "FB":
            scl_output.append(f"// FB{block_number}")
        elif block_type == "FC":
            scl_output.append(f"// FC{block_number}")
        elif block_type == "OB":
            scl_output.append(f"// OB{block_number}")
        else:
            scl_output.append(f"// {block_type}{block_number}")
    elif block_type:
        scl_output.append(f"// {block_type}")

    scl_output.append(f"// Block Type: {block_type}")
    if block_name != scl_block_name:
        scl_output.append(f"// Block Name (Original): {block_name}")
    if block_number:
        scl_output.append(f"// Block Number: {block_number}")
    original_net_langs = set(
        n.get("language", "Unknown") for n in data.get("networks", [])
    )
    scl_output.append(
        f"// Original Network Languages: {', '.join(l for l in original_net_langs if l != 'Unknown')}"
    )
    if block_comment:
        scl_output.append(f"// Block Comment:")
        [scl_output.append(f"//   {line}") for line in block_comment.splitlines()]
    scl_output.append("")
    if block_type == "FC":
        return_type = "Void"
        interface_data = data.get("interface", {})
        if interface_data.get("Return"):
            return_member = interface_data["Return"][0]
            return_type_raw = return_member.get("datatype", "Void")
            return_type = (
                return_type_raw[1:-1]
                if isinstance(return_type_raw, str)
                and return_type_raw.startswith('"')
                and return_type_raw.endswith('"')
                else return_type_raw
            )
            if return_type != return_type_raw and not (
                isinstance(return_type_raw, str)
                and return_type_raw.lower().startswith("array")
            ):
                return_type = f'"{return_type}"'
            else:
                return_type = return_type_raw
        scl_output.append(f'{scl_block_keyword} "{scl_block_name}" : {return_type}')
    else:
        scl_output.append(f'{scl_block_keyword} "{scl_block_name}"')
    scl_output.append("{ S7_Optimized_Access := 'TRUE' }")
    scl_output.append("VERSION : 0.1")
    scl_output.append("")
    return scl_output


# Modificar _generate_scl_interface para pasar project_root_dir
def _generate_scl_interface(interface_data, project_root_dir):  # <-- Nuevo argumento
    """Genera las secciones VAR_* de la interfaz SCL para FC/FB/OB."""
    scl_output = []
    section_order = [
        "Input",
        "Output",
        "InOut",
        "Static",
        "Temp",
        "Constant",
        "Return",
    ]  # Incluir Return
    declared_temps = set()  # Para _generate_scl_temp_vars

    for section_name in section_order:
        vars_in_section = interface_data.get(section_name, [])
        if vars_in_section:
            scl_section_keyword = f"VAR_{section_name.upper()}"
            end_keyword = "END_VAR"
            if section_name == "Static":
                scl_section_keyword = "VAR_STAT"
            if section_name == "Temp":
                scl_section_keyword = "VAR_TEMP"
            if section_name == "Constant":
                scl_section_keyword = "CONSTANT"
                end_keyword = "END_CONSTANT"
            if section_name == "Return":
                scl_section_keyword = "VAR_OUTPUT"
                # Retorno va en Output para FB/OB, implícito en FC

            # Para FC, la sección Return no se declara explícitamente aquí
            if (
                interface_data.get("parent_block_type") == "FC"
                and section_name == "Return"
            ):
                continue

            scl_output.append(scl_section_keyword)
            # Pasar project_root_dir a generate_scl_declarations
            scl_output.extend(
                generate_scl_declarations(
                    vars_in_section, indent_level=1, project_root_dir=project_root_dir
                )
            )  # <-- Pasar ruta raíz
            scl_output.append(end_keyword)
            scl_output.append("")

            if section_name == "Temp":
                declared_temps.update(
                    format_variable_name(v.get("name"))
                    for v in vars_in_section
                    if v.get("name")
                )
    return scl_output, declared_temps


# ... (_generate_scl_temp_vars y _generate_scl_body sin cambios) ...
def _generate_scl_temp_vars(data, declared_temps):
    scl_output = []
    temp_vars_detected = set()
    temp_pattern = re.compile(r'"?(#\w+)"?')
    for network in data.get("networks", []):
        for instruction in network.get("logic", []):
            scl_code = instruction.get("scl", "")
            edge_update_code = instruction.get("_edge_mem_update_scl", "")
            code_to_scan = (
                (scl_code if scl_code else "")
                + "\n"
                + (edge_update_code if edge_update_code else "")
            )
            if code_to_scan:
                found_temps = temp_pattern.findall(code_to_scan)
                [temp_vars_detected.add(t) for t in found_temps if t]
    additional_temps = sorted(list(temp_vars_detected - declared_temps))
    if additional_temps:
        print(f"INFO: Detectadas {len(additional_temps)} VAR_TEMP adicionales.")
        temp_section_exists = any(
            "VAR_TEMP" in s for s in data.get("generated_scl", [])
        )  # Check if VAR_TEMP already exists
        if not temp_section_exists and not declared_temps:
            scl_output.append("VAR_TEMP")  # Only add if no temps were declared before
        for temp_name in additional_temps:
            scl_name = format_variable_name(temp_name)
            inferred_type = "Bool"
            scl_output.append(
                f"  {scl_name} : {inferred_type}; // Auto-generated temporary"
            )
        if not temp_section_exists and not declared_temps:
            scl_output.append("END_VAR")
            scl_output.append("")
    return scl_output


def _generate_scl_body(networks):
    scl_output = ["BEGIN", ""]
    network_logic_added = False
    for i, network in enumerate(networks):
        network_title = network.get("title", f'Network {network.get("id", i+1)}')
        network_comment = network.get("comment", "")
        network_lang = network.get("language", "LAD")
        scl_output.append(
            f"  // Network {i+1}: {network_title} (Original Language: {network_lang})"
        )
        if network_comment:
            [
                scl_output.append(f"  //   {line}")
                for line in network_comment.splitlines()
            ]
        scl_output.append("")
        network_has_code = False
        logic_in_network = network.get("logic", [])
        if not logic_in_network:
            scl_output.append(f"  // Network {i+1} has no logic elements.")
            scl_output.append("")
            continue
        if network_lang == "STL":
            if logic_in_network and logic_in_network[0].get("type") == "RAW_STL_CHUNK":
                network_has_code = True
                raw_stl_code = logic_in_network[0].get(
                    "stl", "// ERROR: STL code missing"
                )
                scl_output.append(f"  // --- BEGIN STL Network {i+1} ---")
                scl_output.append(f"  ```stl ")
                [
                    scl_output.append(
                        f"     {stl_line}"
                    )  # scl_output.append(f"  // {stl_line}")
                    for stl_line in raw_stl_code.splitlines()
                ]
                scl_output.append(f"  ``` ")
                scl_output.append(f"  // --- END STL Network {i+1} ---")
                scl_output.append("")
            else:
                scl_output.append(
                    f"  // ERROR: Contenido STL inesperado en Network {i+1}."
                )
                scl_output.append("")
        else:
            for instruction in logic_in_network:
                instruction_type = instruction.get("type", "")
                scl_code = instruction.get("scl", "")
                is_grouped = instruction.get("grouped", False)
                edge_update_scl = instruction.get("_edge_mem_update_scl", "")
                if is_grouped:
                    continue
                code_to_print = []
                if scl_code:
                    code_to_print.extend(scl_code.splitlines())
                if edge_update_scl:
                    code_to_print.extend(
                        edge_update_scl.splitlines()
                    )  # Append edge update SCL
                if code_to_print:
                    is_only_comment = all(
                        line.strip().startswith("//")
                        for line in code_to_print
                        if line.strip()
                    )
                    is_if_block = any(
                        line.strip().startswith("IF") for line in code_to_print
                    )
                    if (
                        not is_only_comment
                        or is_if_block
                        or "_error" in instruction_type
                        or instruction_type
                        in [
                            "UNSUPPORTED_LANG",
                            "UNSUPPORTED_CONTENT",
                            "PARSING_ERROR",
                            "RAW_SCL_CHUNK",
                        ]
                    ):  # Print RAW_SCL chunks too
                        network_has_code = True
                        [scl_output.append(f"  {line}") for line in code_to_print]
                        scl_output.append("")
        if not network_has_code and network_lang != "STL":
            scl_output.append(f"  // Network {i+1} did not produce printable SCL code.")
            scl_output.append("")
        if network_has_code:
            network_logic_added = True  # Mark if any network had code
    # Add a default comment if no logic was generated at all
    if not network_logic_added:
        scl_output.append("  // No executable logic generated by script.")
        scl_output.append("")
    return scl_output


# Modificar generate_scl_for_code_block para aceptar y pasar project_root_dir
def generate_scl_for_code_block(data, project_root_dir):  # <-- Nuevo argumento
    """Genera el contenido SCL completo para un FC/FB/OB."""
    scl_output = []
    block_type = data.get("block_type", "Unknown")
    scl_block_name = format_variable_name(data.get("block_name", "UnknownBlock"))
    scl_block_keyword = "FUNCTION_BLOCK"  # Default for FB
    if block_type == "FC":
        scl_block_keyword = "FUNCTION"
    elif block_type == "OB":
        scl_block_keyword = "ORGANIZATION_BLOCK"

    scl_output.extend(_generate_scl_header(data, scl_block_name))

    interface_data = data.get("interface", {})
    interface_data["parent_block_type"] = block_type  # Ayuda a _generate_scl_interface
    # Pasar project_root_dir a _generate_scl_interface
    interface_lines, declared_temps = _generate_scl_interface(
        interface_data, project_root_dir
    )  # <-- Pasar ruta raíz
    scl_output.extend(interface_lines)

    # Generar VAR_TEMP adicionales (no necesita project_root_dir)
    scl_output.extend(_generate_scl_temp_vars(data, declared_temps))

    # Generar cuerpo (no necesita project_root_dir)
    scl_output.extend(_generate_scl_body(data.get("networks", [])))
    scl_output.append(f"END_{scl_block_keyword}")

    # Guardar SCL generado en data para _generate_scl_temp_vars
    data["generated_scl"] = scl_output

    return scl_output
