import logging
from os import PathLike
from typing import Any, Optional, Union


class LoraLoggerClass(logging.getLoggerClass()):
    def __generate_extra(
        self,
        *,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ) -> dict:
        extra = dict(id=id, event=event, **kwargs)

        if file:
            extra["file"] = self.__read_file(file)

        return extra

    def __read_file(self, file_name: Union[str, bytes, PathLike]) -> Optional[str]:
        file_content = None

        with open(file_name, "r") as f:
            file_content = f.read()

        return file_content

    def _log(
        self,
        level,
        msg,
        args,
        exc_info=None,
        extra=None,
        stack_info=False,
        stacklevel=1,
    ):
        extra_data = dict(id=None, event=None, file=None)

        if extra is not None and isinstance(extra, dict):
            extra_data.update(extra)  # type: ignore

        super()._log(level, msg, args, exc_info, extra_data, stack_info, stacklevel)

    def debug(
        self,
        msg: Any,
        *args,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ):
        extra = kwargs.get("extra", {})
        extra = {**extra, **self.__generate_extra(id=id, event=event, file=file)}
        kwargs["extra"] = extra

        super().debug(msg, *args, **kwargs)

    def info(
        self,
        msg: Any,
        *args,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ):
        extra = kwargs.get("extra", {})
        extra = {**extra, **self.__generate_extra(id=id, event=event, file=file)}
        kwargs["extra"] = extra

        super().info(msg, *args, **kwargs)

    def warning(
        self,
        msg: Any,
        *args,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ):
        extra = kwargs.get("extra", {})
        extra = {**extra, **self.__generate_extra(id=id, event=event, file=file)}
        kwargs["extra"] = extra

        super().warning(msg, *args, **kwargs)

    def error(
        self,
        msg: Any,
        *args,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ):
        extra = kwargs.get("extra", {})
        extra = {**extra, **self.__generate_extra(id=id, event=event, file=file)}
        kwargs["extra"] = extra

        super().error(msg, *args, **kwargs)

    def exception(
        self,
        msg: Any,
        *args,
        exc_info=True,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ):
        extra = kwargs.get("extra", {})
        extra = {**extra, **self.__generate_extra(id=id, event=event, file=file)}
        kwargs["extra"] = extra

        super().exception(msg, *args, exc_info=exc_info, **kwargs)

    def critical(
        self,
        msg: Any,
        *args,
        id: Optional[str] = None,
        event: Optional[str] = None,
        file: Union[str, bytes, PathLike, None] = None,
        **kwargs,
    ):
        extra = kwargs.get("extra", {})
        extra = {**extra, **self.__generate_extra(id=id, event=event, file=file)}
        kwargs["extra"] = extra

        super().critical(msg, *args, **kwargs)
