"""
export_logic_from_tia : Script para exportar el software de un PLC desde TIA Portal en archivos XML y SCL.
"""

import tkinter as tk
from tkinter import filedialog
import os
import sys
import traceback

script_root = os.path.dirname(
    os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
)
sys.path.append(script_root)
from backend.script_utils import load_configuration

# --- Configuration ---
TIA_PORTAL_VERSION = "18.0"  # Target TIA Portal version (e.g., "18.0")
EXPORT_OPTIONS = None  # Use default export options
KEEP_FOLDER_STRUCTURE = (
    True  # Replicate TIA project folder structure in export directory
)

# --- TIA Scripting Import Handling ---
# Check if the TIA_SCRIPTING environment variable is set
if os.getenv("TIA_SCRIPTING"):
    sys.path.append(os.getenv("TIA_SCRIPTING"))
else:
    # Optional: Define a fallback path if the environment variable isn't set
    # fallback_path = "C:\\path\\to\\your\\TIA_Scripting_binaries"
    # if os.path.exists(fallback_path):
    #     sys.path.append(fallback_path)
    pass  # Allow import to fail if not found

try:
    import siemens_tia_scripting as ts

    EXPORT_OPTIONS = (
        ts.Enums.ExportOptions.WithDefaults
    )  # Set default options now that 'ts' is imported
except ImportError:
    print("ERROR: Failed to import 'siemens_tia_scripting'.")
    print("Ensure:")
    print(f"1. TIA Portal Openness for V{TIA_PORTAL_VERSION} is installed.")
    print(
        "2. The 'siemens_tia_scripting' Python module is installed (pip install ...) or"
    )
    print(
        "   the path to its binaries is set in the 'TIA_SCRIPTING' environment variable."
    )
    print(
        "3. You are using a compatible Python version (e.g., 3.12.X as per documentation)."
    )
    sys.exit(1)
except Exception as e:
    print(f"An unexpected error occurred during import: {e}")
    traceback.print_exc()
    sys.exit(1)

# --- Functions ---


def select_project_file():
    """Opens a dialog to select a TIA Portal project file."""
    root = tk.Tk()
    root.withdraw()  # Hide the main tkinter window
    file_path = filedialog.askopenfilename(
        title="Select TIA Portal Project File",
        filetypes=[
            (
                f"TIA Portal V{TIA_PORTAL_VERSION} Projects",
                f"*.ap{TIA_PORTAL_VERSION.split('.')[0]}",
            )
        ],  # e.g. *.ap18
    )
    root.destroy()
    if not file_path:
        print("No project file selected. Exiting.")
        sys.exit(0)
    return file_path


def select_export_directory():
    """Opens a dialog to select the export directory."""
    root = tk.Tk()
    root.withdraw()  # Hide the main tkinter window
    dir_path = filedialog.askdirectory(title="Select Export Directory")
    root.destroy()
    if not dir_path:
        print("No export directory selected. Exiting.")
        sys.exit(0)
    return dir_path


def export_plc_data(plc, export_base_dir):
    """Exports Blocks, UDTs, and Tag Tables from a given PLC."""
    plc_name = plc.get_name()
    print(f"\n--- Processing PLC: {plc_name} ---")

    # Define base export path for this PLC
    plc_export_dir = os.path.join(export_base_dir, plc_name)
    os.makedirs(plc_export_dir, exist_ok=True)

    # --- Export Program Blocks ---
    blocks_exported = 0
    blocks_skipped = 0
    print(f"\n[PLC: {plc_name}] Exporting Program Blocks...")
    xml_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_XML")
    scl_blocks_path = os.path.join(plc_export_dir, "ProgramBlocks_SCL")
    os.makedirs(xml_blocks_path, exist_ok=True)
    os.makedirs(scl_blocks_path, exist_ok=True)
    print(f"  XML Target: {xml_blocks_path}")
    print(f"  SCL Target: {scl_blocks_path}")

    try:
        program_blocks = plc.get_program_blocks()  #
        print(f"  Found {len(program_blocks)} program blocks.")
        for block in program_blocks:
            block_name = block.get_name()  # Assuming get_name() exists
            print(f"    Processing block: {block_name}...")
            try:
                if not block.is_consistent():  #
                    print(f"      Compiling block {block_name}...")
                    block.compile()  #
                    if not block.is_consistent():
                        print(
                            f"      WARNING: Block {block_name} inconsistent after compile. Skipping."
                        )
                        blocks_skipped += 1
                        continue

                print(f"      Exporting {block_name} as XML...")
                block.export(
                    target_directory_path=xml_blocks_path,  #
                    export_options=EXPORT_OPTIONS,  #
                    export_format=ts.Enums.ExportFormats.SimaticML,  #
                    keep_folder_structure=KEEP_FOLDER_STRUCTURE,
                )  #

                try:
                    prog_language = block.get_property(name="ProgrammingLanguage")
                    if prog_language == "SCL":
                        print(f"      Exporting {block_name} as SCL...")
                        block.export(
                            target_directory_path=scl_blocks_path,
                            export_options=EXPORT_OPTIONS,
                            export_format=ts.Enums.ExportFormats.ExternalSource,  #
                            keep_folder_structure=KEEP_FOLDER_STRUCTURE,
                        )
                except Exception as prop_ex:
                    print(
                        f"      Could not get ProgrammingLanguage for {block_name}. Skipping SCL. Error: {prop_ex}"
                    )

                blocks_exported += 1
            except Exception as block_ex:
                print(f"      ERROR exporting block {block_name}: {block_ex}")
                blocks_skipped += 1
        print(
            f"  Program Blocks Export Summary: Exported={blocks_exported}, Skipped/Errors={blocks_skipped}"
        )
    except Exception as e:
        print(f"  ERROR processing Program Blocks: {e}")
        traceback.print_exc()

    # --- Export PLC Data Types (UDTs) ---
    udts_exported = 0
    udts_skipped = 0
    print(f"\n[PLC: {plc_name}] Exporting PLC Data Types (UDTs)...")
    udt_export_path = os.path.join(plc_export_dir, "PlcDataTypes")
    os.makedirs(udt_export_path, exist_ok=True)
    print(f"  Target: {udt_export_path}")

    try:
        udts = plc.get_user_data_types()  #
        print(f"  Found {len(udts)} UDTs.")
        for udt in udts:
            udt_name = udt.get_name()  #
            print(f"    Processing UDT: {udt_name}...")
            try:
                if not udt.is_consistent():  #
                    print(f"      Compiling UDT {udt_name}...")
                    udt.compile()  #
                    if not udt.is_consistent():
                        print(
                            f"      WARNING: UDT {udt_name} inconsistent after compile. Skipping."
                        )
                        udts_skipped += 1
                        continue

                print(f"      Exporting {udt_name}...")
                udt.export(
                    target_directory_path=udt_export_path,  #
                    export_options=EXPORT_OPTIONS,  #
                    # export_format defaults to SimaticML for UDTs
                    keep_folder_structure=KEEP_FOLDER_STRUCTURE,
                )  #
                udts_exported += 1
            except Exception as udt_ex:
                print(f"      ERROR exporting UDT {udt_name}: {udt_ex}")
                udts_skipped += 1
        print(
            f"  UDT Export Summary: Exported={udts_exported}, Skipped/Errors={udts_skipped}"
        )
    except Exception as e:
        print(f"  ERROR processing UDTs: {e}")
        traceback.print_exc()

    # --- Export PLC Tag Tables ---
    tags_exported = 0
    tags_skipped = 0
    print(f"\n[PLC: {plc_name}] Exporting PLC Tag Tables...")
    tags_export_path = os.path.join(plc_export_dir, "PlcTags")
    os.makedirs(tags_export_path, exist_ok=True)
    print(f"  Target: {tags_export_path}")

    try:
        tag_tables = plc.get_plc_tag_tables()  #
        print(f"  Found {len(tag_tables)} Tag Tables.")
        for table in tag_tables:
            table_name = table.get_name()  #
            print(f"    Processing Tag Table: {table_name}...")
            try:
                # Note: Consistency check might not be available/needed for tag tables like blocks/UDTs
                print(f"      Exporting {table_name}...")
                table.export(
                    target_directory_path=tags_export_path,  #
                    export_options=EXPORT_OPTIONS,  #
                    # export_format defaults to SimaticML for Tag Tables
                    keep_folder_structure=KEEP_FOLDER_STRUCTURE,
                )  #
                tags_exported += 1
            except Exception as table_ex:
                print(f"      ERROR exporting Tag Table {table_name}: {table_ex}")
                tags_skipped += 1
        print(
            f"  Tag Table Export Summary: Exported={tags_exported}, Skipped/Errors={tags_skipped}"
        )
    except Exception as e:
        print(f"  ERROR processing Tag Tables: {e}")
        traceback.print_exc()

    print(f"\n--- Finished processing PLC: {plc_name} ---")


# --- Main Script ---


if __name__ == "__main__":
    configs = load_configuration()
    working_directory = configs.get("working_directory")

    print("--- TIA Portal Data Exporter (Blocks, UDTs, Tags) ---")

    # Validate working directory
    if not working_directory or not os.path.isdir(working_directory):
        print("ERROR: Working directory not set or invalid in configuration.")
        print("Please configure the working directory using the main application.")
        sys.exit(1)

    # 1. Select Project File, Export Directory comes from config
    project_file = select_project_file()
    export_dir = working_directory  # Use working directory from config

    print(f"\nSelected Project: {project_file}")
    print(f"Using Export Directory (Working Directory): {export_dir}")

    portal_instance = None
    project_object = None

    try:
        # 2. Connect to TIA Portal
        print(f"\nConnecting to TIA Portal V{TIA_PORTAL_VERSION}...")
        portal_instance = ts.open_portal(
            version=TIA_PORTAL_VERSION,
            portal_mode=ts.Enums.PortalMode.WithGraphicalUserInterface,
        )
        print("Connected to TIA Portal.")
        print(f"Portal Process ID: {portal_instance.get_process_id()}")  #

        # 3. Open Project
        print(f"Opening project: {os.path.basename(project_file)}...")
        project_object = portal_instance.open_project(project_file_path=project_file)  #
        if project_object is None:
            print("Project might already be open, attempting to get handle...")
            project_object = portal_instance.get_project()  #
            if project_object is None:
                raise Exception("Failed to open or get the specified project.")
        print("Project opened successfully.")

        # 4. Get PLCs
        plcs = project_object.get_plcs()  #
        if not plcs:
            print("No PLC devices found in the project.")
        else:
            print(f"Found {len(plcs)} PLC(s). Starting export process...")

            # 5. Iterate and Export Data for each PLC
            for plc_device in plcs:
                export_plc_data(
                    plc=plc_device, export_base_dir=export_dir
                )  # Pass export_dir

        print("\nExport process completed.")

    except ts.TiaException as tia_ex:
        print(f"\nTIA Portal Openness Error: {tia_ex}")
        traceback.print_exc()
    except FileNotFoundError:
        print(f"\nERROR: Project file not found at {project_file}")
    except Exception as e:
        print(f"\nAn unexpected error occurred: {e}")
        traceback.print_exc()
    finally:
        # 6. Cleanup
        if portal_instance:
            try:
                print("\nClosing TIA Portal...")
                portal_instance.close_portal()  #
                print("TIA Portal closed.")
            except Exception as close_ex:
                print(f"Error during TIA Portal cleanup: {close_ex}")

        print("\nScript finished.")
