#!/usr/bin/env python3
import argparse
import csv
import faulthandler
import logging
import os
import platform
import signal
import sys
sys.argv.append("--sim-io")
#sys.argv.append("--system-id=test-windows")

if platform.system().lower() == "windows":
    sys.path.append(f"{os.getcwd()}\src\components")
    sys.path.append(f"{os.getcwd()}\src")
else:
    sys.path.append(f"{os.getcwd()}/src/components")

import traceback
import weakref
from datetime import datetime
from pathlib import Path
from ui.diagnostics import Diagnostics
from lib.helpers.single_process import SingleProcess


app = None

parser = argparse.ArgumentParser(prog='ST-TEN', description='Leak test system')
parser.add_argument('-s', '--system-id')
args, unspec = parser.parse_known_args()

def quit_app(signalnum=None, handler=None):
    logging.info(f"quitting app. signal: {signalnum!r}, handler: {handler!r}")
    global app
    if app is not None:
        app.quit()
    quit()


# SETUP QUITTING ON CTRL+C
signal.signal(signal.SIGINT, quit_app)

# SETUP FAULTHANDLER
faulthandler.enable(file=sys.stderr, all_threads=True)

# SETUP LOGS
logs_dir = Path(".") / "data" / "logs"
os.makedirs(logs_dir, exist_ok=True)
logging.basicConfig(
    format="{asctime}:{name}:{levelname}:{message}",
    datefmt="%Y-%m-%d_%H-%M-%S",
    style="{",
    level="DEBUG" if "--debug" in sys.argv else "INFO",
    handlers=[
        logging.StreamHandler(stream=sys.stderr),
        logging.FileHandler(
            logs_dir / f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log",
            mode="a",
            encoding="utf-8",
            delay=False,
            **({"errors": "surrogateescape"} if sys.version_info.major >= 3 and sys.version_info.minor >= 10 else {}),
        ),
    ],
    force=True,
    **({"encoding": "utf-8"} if sys.version_info.major >= 3 and sys.version_info.minor >= 10 else {}),
    **({"errors": "surrogateescape"} if sys.version_info.major >= 3 and sys.version_info.minor >= 10 else {}),
)

try:
    # IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGING
    from components import TecnaMarpossProvasetT3
    from lib.db import Users
    from lib.helpers import ConfigReader
    from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot
    from PyQt5.QtWidgets import QApplication, QMessageBox, QFileDialog
    from ui import About, Archive, Login, Main_Window, Test, Users_Management, Recipe_Selection, \
        Barcode_Recipe_Selection



    class Main(QObject):

        def __init__(self, parent=None):
            # print(f"MAIN   {int(QThread.currentThreadId())}", flush=True)
            super().__init__()
            self.recipes = None
            try:
                # READ CONFIG

                system_id = args.system_id if "system_id" in args else None

                self.config = ConfigReader(system_id=system_id)
                logging.info(f"STARTING SESSION ON MACHINE {self.config['machine']['description']}")
                # INIT COMPONENT
                self.components_specs = {
                    "tecna_t3": {"c": TecnaMarpossProvasetT3, "k": {"paused": True}},
                }

                self.components = {}
                self.threads = {}
                for component_name, spec in self.components_specs.items():
                    self.components[component_name] = spec["c"](*spec.get("a", []), config=self.config,
                                                                name=component_name, **spec.get("k", {}))
                    if spec.get("t", True):
                        self.threads[component_name] = QThread()
                        self.threads[component_name].setTerminationEnabled(True)
                        self.components[component_name].moveToThread(self.threads[component_name])

                for component_name, thread in self.threads.items():
                    component = self.components[component_name]
                    thread.started.connect(component.start)
                    thread.start()
                    # DEBUGGER WORKAROUND
                    QApplication.processEvents()
                    QThread.msleep(1000)
                    QApplication.processEvents()
                    component.wait_completion()

            except Exception as e:
                logging.exception(traceback.format_exc())
                QMessageBox.critical(None, "Errore", f"Errore di avvio del programma di collaudo:\n\n{e}")
                quit()

        def read_recipes(self):
            self.recipes = {}
            max_num_recipes=self.components["tecna_t3"].max_program_number
            max_num_recipes=300
            logging.info(f"NUMBER OF RECIPES TO BE READ: {max_num_recipes}")
            for recipe_num in range(1, max_num_recipes+1):
                logging.info(f"READING RECIPE #{recipe_num}")
                self.recipes[recipe_num] = self.components["tecna_t3"].read_recipe(recipe_num)

        def export_recipes(self, csv_path=None):
            if csv_path is None:
                csv_path, _ = QFileDialog.getSaveFileName(
                    None,
                    "Esportazione ricette",
                    "ricette.csv",
                    "CSV data (*.csv);;All Files (*)",
                )
            csv_path = str(csv_path)
            if not len(csv_path):
                return
            if not csv_path.lower().endswith(".csv"):
                csv_path += ".csv"
            csv_dir = os.path.dirname(csv_path)
            if len(csv_dir):
                os.makedirs(csv_dir, exist_ok=True)
            data = []
            fieldnames = [
                "codice_ricetta",
                "part_number",
                "tempo_pre_riempimento",
                "pressione_pre_riempimento",
                "tempo_riempimento",
                "tempo_assestamento",
                "percentuale_minima_pressione_assestamento",
                "percentuale_massima_pressione_assestamento",
                "tempo_di_test",
                "pressione_di_test_delta_minimo",
                "pressione_di_test",
                "pressione_di_test_delta_massimo",
                "tempo_svuotamento",
                "pressione_svuotamento",
                "template_di_stampa",
                "campo1",
                "campo2"
            ]
            for num,recipe in self.recipes.items():
                exportable = {
                    "codice_ricetta": recipe["recipe_name"],
                    "part_number": recipe["recipe_code"],
                    "campo1": recipe["recipe_f1"],
                    "campo2": recipe["recipe_f2"],
                    "tempo_pre_riempimento": recipe["pre_filling_time"],
                    "pressione_pre_riempimento": recipe["pre_filling_pressure"],
                    "tempo_riempimento": recipe["filling_time"],
                    "tempo_assestamento": recipe["settling_time"],
                    "percentuale_minima_pressione_assestamento": recipe["settling_pressure_min_percent"],
                    "percentuale_massima_pressione_assestamento": recipe["settling_pressure_max_percent"],
                    "tempo_di_test": recipe["test_time"],
                    "pressione_di_test_delta_minimo": recipe["test_pressure_qneg"],
                    "pressione_di_test": recipe["test_pressure"],
                    "pressione_di_test_delta_massimo": recipe["test_pressure_qpos"],
                    "tempo_svuotamento": recipe["flush_time"],
                    "pressione_svuotamento": recipe["flush_pressure"],
                    "template_di_stampa": recipe["print_template"],
                }
                data.append(exportable)
            if len(data):
                logging.info(f"recipes: exporting recipes to {csv_path}")
                with open(csv_path, "w", newline="") as f:
                    w = csv.DictWriter(f, fieldnames, extrasaction="ignore")
                    w.writeheader()
                    w.writerows(data)
                logging.info(f"recipes: exported {len(data)} rows.")


    if __name__ == "__main__":
        app = QApplication(sys.argv)

        with SingleProcess() as single_process_lock:

            main = Main()
            main.read_recipes()
            main.export_recipes()


except Exception:
    logging.exception(traceback.format_exc())
