from __future__ import annotations

import datetime
import logging
import sys
import warnings
from dataclasses import dataclass
from pathlib import Path

from sklearn.exceptions import ConvergenceWarning

DAJIN_RESULTS_DIR = Path("DAJIN_Results")
TEMP_ROOT_DIR = Path(DAJIN_RESULTS_DIR, ".tempdir")


@dataclass(frozen=True)
class ConsensusKey:
    allele: str
    label: int
    percent: float


class DeferredFileHandler(logging.FileHandler):
    def __init__(self, filename, mode="a", encoding=None, delay=True):
        # Setting delay to True to defer the file opening
        super().__init__(filename, mode, encoding, delay)

    def emit(self, record):
        # The file is actually opened when a log is emitted
        if self.stream is None:
            self.stream = self._open()
        super().emit(record)


def get_logfile() -> Path:
    current_time = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")
    return Path(f"DAJIN2_log_{current_time}.txt")


def set_logging(path_logfile: Path, level: int = logging.INFO) -> logging.Logger:
    log_format = "%(asctime)s, %(levelname)s, %(message)s"
    date_format = "%Y-%m-%d %H:%M:%S"

    stderr_handler = logging.StreamHandler()
    stderr_handler.setFormatter(logging.Formatter(log_format, datefmt=date_format))

    file_handler = DeferredFileHandler(path_logfile)
    file_handler.setFormatter(logging.Formatter(log_format, datefmt=date_format))

    logging.basicConfig(level=level, handlers=[stderr_handler, file_handler])

    # Drop noisy kaleido Chromium launch message (see issue #117)
    def _suppress_chromium_init(record: logging.LogRecord) -> bool:
        return "Chromium init'ed with kwargs" not in record.getMessage()

    chromium_filter = logging.Filter()
    chromium_filter.filter = _suppress_chromium_init
    stderr_handler.addFilter(chromium_filter)
    file_handler.addFilter(chromium_filter)

    # log uncaught exceptions
    def handle_uncaught_exception(exc_type, exc_value, exc_traceback):
        logging.error("Catch an Exception. Traceback:", exc_info=(exc_type, exc_value, exc_traceback))

    sys.excepthook = handle_uncaught_exception

    return logging.getLogger(__name__)


def reset_logging() -> None:
    """
    Reset the logging system to its default state.
    """
    # Remove all existing handlers
    for handler in logging.root.handlers[:]:
        logging.root.removeHandler(handler)


def set_warnings_ignore() -> None:
    warnings.filterwarnings("ignore", category=RuntimeWarning)
    warnings.filterwarnings("ignore", category=FutureWarning)
    warnings.filterwarnings("ignore", category=UserWarning)
    warnings.filterwarnings("ignore", category=ConvergenceWarning)
