from enum import Enum  # noqa: I001
from importlib.util import find_spec
from pathlib import Path
from typing import Final
import os

from sentence_transformers import SimilarityFunction

from lang_main import CONFIG, CYTO_PATH_STYLESHEET, BASE_PATH
from lang_main.types import (
    CytoLayoutProperties,
    CytoLayouts,
    ONNXExecutionProvider,  # noqa: F401
    STFRBackends,
    STFRDeviceTypes,
    STFRModelArgs,
    STFRModelTypes,
    STFRQuantFilenames,  # noqa: F401
    SpacyModelTypes,
)

__all__ = [
    'CONFIG',
    'CYTO_PATH_STYLESHEET',
]

# ** dependencies
_has_py4cyto: bool = True if find_spec('py4cytoscape') else False
_has_dash: bool = True if (find_spec('dash') and find_spec('kaleido')) else False
_has_plotly: bool = True if (find_spec('plotly') and find_spec('kaleido')) else False


class Dependencies(Enum):
    PY4C = _has_py4cyto
    DASH = _has_dash
    PLOT = _has_plotly


# ** logging
# graphs
ENABLE_LOGGING: Final[bool] = CONFIG['logging']['enabled']
LOGGING_TO_FILE: Final[bool] = CONFIG['logging']['file']
LOGGING_TO_STDERR: Final[bool] = CONFIG['logging']['stderr']
LOGGING_DEFAULT_GRAPHS: Final[bool] = False

# ** pickling
PICKLE_PROTOCOL_VERSION: Final[int] = 5

# ** paths
input_path_conf = Path.cwd() / Path(CONFIG['paths']['inputs'])
INPUT_PATH_FOLDER: Final[Path] = input_path_conf.resolve()
# TODO reactivate later
# if not INPUT_PATH_FOLDER.exists():
#     raise FileNotFoundError(f'Input path >>{INPUT_PATH_FOLDER}<< does not exist.')
save_path_conf = Path.cwd() / Path(CONFIG['paths']['results'])
SAVE_PATH_FOLDER: Final[Path] = save_path_conf.resolve()
path_dataset_conf = Path.cwd() / Path(CONFIG['paths']['dataset'])
PATH_TO_DATASET: Final[Path] = path_dataset_conf.resolve()
# if not PATH_TO_DATASET.exists():
#     raise FileNotFoundError(f'Dataset path >>{PATH_TO_DATASET}<< does not exist.')
# ** control
SKIP_PREPROCESSING: Final[bool] = CONFIG['control']['preprocessing_skip']
SKIP_TOKEN_ANALYSIS: Final[bool] = CONFIG['control']['token_analysis_skip']
SKIP_GRAPH_POSTPROCESSING: Final[bool] = CONFIG['control']['graph_postprocessing_skip']
SKIP_GRAPH_RESCALING: Final[bool] = CONFIG['control']['graph_rescaling_skip']
SKIP_GRAPH_STATIC_RENDERING: Final[bool] = CONFIG['control']['graph_static_rendering_skip']
SKIP_TIME_ANALYSIS: Final[bool] = CONFIG['control']['time_analysis_skip']


# ** models
# ** loading
MODEL_BASE_FOLDER_NAME: Final[str] = 'lang-models'
MODEL_BASE_FOLDER: Final[Path] = BASE_PATH / MODEL_BASE_FOLDER_NAME
if not MODEL_BASE_FOLDER.exists():
    raise FileNotFoundError('Language model folder not found.')
os.environ['SENTENCE_TRANSFORMERS_HOME'] = str(MODEL_BASE_FOLDER)
SPACY_MODEL_NAME: Final[SpacyModelTypes] = SpacyModelTypes.DE_DEP_NEWS_TRF
STFR_MODEL_NAME: Final[STFRModelTypes] = STFRModelTypes.ALL_MPNET_BASE_V2
STFR_DEVICE: Final[STFRDeviceTypes] = STFRDeviceTypes.CPU
STFR_SIMILARITY: Final[SimilarityFunction] = SimilarityFunction.COSINE
STFR_BACKEND: Final[STFRBackends] = STFRBackends.TORCH
STFR_MODEL_ARGS_DEFAULT: STFRModelArgs = {}
STFR_MODEL_ARGS_ONNX: STFRModelArgs = {
    'file_name': STFRQuantFilenames.ONNX_Q_UINT8,
    'provider': ONNXExecutionProvider.CPU,
    'export': False,
}
stfr_model_args: STFRModelArgs
if STFR_BACKEND == STFRBackends.ONNX:
    stfr_model_args = STFR_MODEL_ARGS_ONNX
else:
    stfr_model_args = STFR_MODEL_ARGS_DEFAULT

STFR_MODEL_ARGS: Final[STFRModelArgs] = stfr_model_args
# ** language dependency analysis
# ** POS
POS_OF_INTEREST: frozenset[str] = frozenset(['NOUN', 'PROPN', 'VERB', 'AUX', 'ADV', 'NUM'])
POS_INDIRECT: frozenset[str] = frozenset(['AUX'])
# ** TAG
# TAG_OF_INTEREST: frozenset[str] = frozenset(['ADJD'])
TAG_OF_INTEREST: frozenset[str] = frozenset()


# ** export
# ** preprocessing
DATE_COLS: Final[list[str]] = CONFIG['preprocess']['date_cols']
THRESHOLD_AMOUNT_CHARACTERS: Final[float] = CONFIG['preprocess'][
    'threshold_amount_characters'
]
THRESHOLD_SIMILARITY: Final[float] = CONFIG['preprocess']['threshold_similarity']
# ** token analysis

# ** graph postprocessing
EDGE_WEIGHT_DECIMALS: Final[int] = 4
THRESHOLD_EDGE_NUMBER: Final[int] = CONFIG['graph_postprocessing']['threshold_edge_number']
PROPERTY_NAME_DEGREE_WEIGHTED: Final[str] = 'degree_weighted'

# ** graph exports (Cytoscape)
CYTO_MAX_NODE_COUNT: Final[int] = 500
CYTO_MAX_EDGE_COUNT: Final[int] = 800
CYTO_COLLECTION_NAME: Final[str] = 'lang_main'
CYTO_BASE_NETWORK_NAME: Final[str] = 'token_graph'
CYTO_LAYOUT_NAME: Final[CytoLayouts] = 'force-directed'
CYTO_LAYOUT_PROPERTIES: Final[CytoLayoutProperties] = {
    'numIterations': 1000,
    'defaultSpringCoefficient': 1e-4,
    'defaultSpringLength': 45,
    'defaultNodeMass': 11,
    'isDeterministic': True,
    'singlePartition': False,
}
CYTO_SANDBOX_NAME: Final[str] = 'lang_main'
CYTO_STYLESHEET_NAME: Final[str] = 'lang_main'
# name for property, on which selection is done
CYTO_SELECTION_PROPERTY: Final[str] = 'node_selection'
CYTO_NUMBER_SUBGRAPHS: Final[int] = 5
CYTO_ITER_NEIGHBOUR_DEPTH: Final[int] = 2
CYTO_NETWORK_ZOOM_FACTOR: Final[float] = 0.96

# ** time_analysis.uniqueness
THRESHOLD_UNIQUE_TEXTS: Final[int] = CONFIG['time_analysis']['uniqueness'][
    'threshold_unique_texts'
]
UNIQUE_CRITERION_FEATURE: Final[str] = CONFIG['time_analysis']['uniqueness'][
    'criterion_feature'
]
FEATURE_NAME_OBJ_ID: Final[str] = CONFIG['time_analysis']['uniqueness']['feature_name_obj_id']
FEATURE_NAME_OBJ_TEXT: Final[str] = CONFIG['time_analysis']['uniqueness'][
    'feature_name_obj_text'
]
# ** time_analysis.preparation
# NAME_DELTA_FEAT_TO_REPAIR: Final[str] = 'delta_to_repair'
CONFIG['time_analysis']['preparation']['name_delta_feat_to_repair']
NAME_DELTA_FEAT_TO_REPAIR: Final[str] = CONFIG['time_analysis']['preparation'][
    'name_delta_feat_to_repair'
]
NAME_DELTA_FEAT_TO_NEXT_FAILURE: Final[str] = CONFIG['time_analysis']['preparation'][
    'name_delta_feat_to_next_failure'
]
# ** time_analysis.model_input
MODEL_INPUT_FEATURES: Final[tuple[str, ...]] = tuple(
    CONFIG['time_analysis']['model_input']['input_features']
)
ACTIVITY_FEATURE: Final[str] = CONFIG['time_analysis']['model_input']['activity_feature']
ACTIVITY_TYPES: Final[tuple[str, ...]] = tuple(
    CONFIG['time_analysis']['model_input']['activity_types']
)
THRESHOLD_NUM_ACTIVITIES: Final[int] = CONFIG['time_analysis']['model_input'][
    'threshold_num_acitivities'
]
THRESHOLD_TIMELINE_SIMILARITY: Final[float] = CONFIG['time_analysis']['model_input'][
    'threshold_similarity'
]
