import os
from sqlalchemy.orm import Session
from sqlalchemy.sql import text
from .model.historian import Historian
from .model.signal_type import SignalType
from typing import Dict, Final
from config import get_clean_identifier


class ProcessParameters:
    def __init__(
        self,
        cim_export_file_path: str,
        device_csv_file_path: str,
        default_dnp3_port: int,
        session: Session,
        is_sql_server: bool,
        target_source: str,
        company_acronym: str,
        ieee_c37_118_version: int,
        map_quality_to_state_flags: bool,
        publish_flags_as_separate_measurements: bool,
        tag_match_pattern: str,
        quality_tag_suffix: str,
        polling_interval: float,
        valid_time_range: float,
        output_directory: str,
        template_directory: str,
        tag_map_directory: str,
        comment_char: str,
    ):
        self.session: Final[Session] = session

        self.is_sql_server: Final[bool] = is_sql_server

        self.cim_export_file_path: Final[str] = cim_export_file_path

        self.device_csv_file_path: Final[str] = device_csv_file_path

        self.default_dnp3_port: Final[int] = default_dnp3_port

        self.target_source: Final[str] = target_source

        self.company_acronym: Final[str] = get_clean_identifier(company_acronym)

        self.ieee_c37_118_version: Final[int] = ieee_c37_118_version

        self.map_quality_to_state_flags: Final[bool] = map_quality_to_state_flags

        self.publish_flags_as_separate_measurements: Final[bool] = publish_flags_as_separate_measurements

        self.tag_match_pattern: Final[str] = tag_match_pattern

        self.quality_tag_suffix: Final[str] = quality_tag_suffix

        self.polling_interval: Final[float] = polling_interval

        self.valid_time_range: Final[float] = valid_time_range

        self.output_directory: Final[str] = output_directory

        if self.output_directory[-1] != "/":
            self.output_directory += "/"

        # Make sure output directory exists
        if not os.path.exists(output_directory):
            os.makedirs(output_directory)

        if template_directory[-1] != "/":
            template_directory += "/"

        self.tag_map_directory: Final[str] = tag_map_directory

        if self.tag_map_directory[-1] != "/":
            self.tag_map_directory += "/"

        # Make sure tag map directory exists
        if not os.path.exists(tag_map_directory):
            os.makedirs(tag_map_directory)

        # Load 'Device.xml' template into a string
        with open(f"{template_directory}Device.xml", "r") as device_template_file:
            self.device_template: Final[str] = device_template_file.read()

        # Load 'IndexMap.xml' template into a string
        with open(f"{template_directory}IndexMap.xml", "r") as index_map_template_file:
            self.index_map_template: Final[str] = index_map_template_file.read()

        # Load 'Mapping.xml' template into a string
        with open(f"{template_directory}Mapping.xml", "r") as mapping_template_file:
            self.mapping_template: Final[str] = mapping_template_file.read()

        # Lookup default node ID
        node_id = session.execute(text("SELECT ID FROM Node WHERE Name = 'Default'")).scalar()

        if not node_id:
            node_id = session.execute(text("SELECT TOP 1 ID FROM Node")).scalar()

        if not node_id:
            raise Exception("failed to load default node ID")

        self.node_id: Final[str] = str(node_id)

        # Lookup target historian ID
        historian_record = session.query(Historian).filter(Historian.Acronym == target_source).one_or_none()

        if not historian_record:
            raise Exception(f'failed to load historian record for "target_source": "{target_source}"')

        self.historian_id: Final[int] = int(historian_record.ID)

        # Lookup DNP3 protocol ID
        protocol_id = session.execute(text("SELECT ID FROM Protocol WHERE Acronym = 'DNP3'")).scalar()

        if not protocol_id:
            raise Exception("failed to load DNP3 protocol ID")

        self.protocol_id: Final[int] = int(protocol_id)

        signal_type_ids = {}

        signal_type_ids["ALOG"] = self.lookup_signal_type_id("ALOG")
        signal_type_ids["DIGI"] = self.lookup_signal_type_id("DIGI")
        signal_type_ids["CALC"] = self.lookup_signal_type_id("CALC")

        self.signal_type_ids: Final[Dict[str, int]] = signal_type_ids

        self.comment_char: Final[str] = comment_char

    def lookup_signal_type_id(self, signal_type: str) -> int:
        signal_type_record = self.session.query(SignalType).filter(SignalType.Acronym == signal_type).one_or_none()

        if not signal_type_record:
            raise Exception(f'failed to load signal type record for "signal_type": "{signal_type}"')

        return signal_type_record.ID  # pyright: ignore[reportReturnType]
