from datetime import timezone, datetime, timedelta, date
import logging
import re
import uuid
from time import time

import aiohttp
from aiohttp import ClientResponse
from logging_loki import LokiHandler
from pythonjsonlogger import jsonlogger

from tp_helper.types.env_type import EnvType


# class TaggedLogFilter(logging.Filter):
#     """Filter that wraps extra dict in tags key on LogRecord before handlers process it.
#
#     Filters run before handlers, ensuring tags are set on the LogRecord
#     before Loki or other handlers process it.
#     """
#
#     _STANDARD_ATTRS = {
#         'name', 'msg', 'args', 'created', 'filename', 'funcName', 'levelname',
#         'levelno', 'lineno', 'module', 'msecs', 'message', 'pathname',
#         'process', 'processName', 'relativeCreated', 'thread', 'threadName',
#         'exc_info', 'exc_text', 'stack_info', 'asctime', 'extra', 'tags',
#         'taskName'
#     }
#
#     def __init__(self, job: str | uuid.UUID | int | None = None):
#         """Initialize filter with optional job to add to tags."""
#         super().__init__()
#         self.job = job
#
#     def filter(self, record: logging.LogRecord):
#         """Transform the record by wrapping extra fields in tags."""
#         # Start with existing tags if present, or empty dict
#         if hasattr(record, 'tags') and isinstance(record.tags, dict):
#             tags = record.tags.copy()
#         else:
#             tags = {}
#
#         # Find all non-standard attributes (these come from extra parameter)
#         extra_fields = {k: v for k, v in record.__dict__.items()
#                         if k not in self._STANDARD_ATTRS}
#
#         # If user explicitly passed extra={"tags": {...}}, use that as base
#         if 'tags' in extra_fields and isinstance(extra_fields['tags'], dict):
#             tags.update(extra_fields['tags'])
#             # Remove 'tags' from extra_fields so we don't add it again
#             del extra_fields['tags']
#
#         # Add label to tags if provided (label takes precedence if already in tags)
#         if self.job:
#             tags['job'] = self.job
#
#         # Merge remaining extra fields into tags
#         if extra_fields:
#             tags.update(extra_fields)
#
#         # Set tags on record if we have any
#         if tags:
#             record.tags = tags
#
#         return True



def get_full_class_name(obj):
    module = obj.__class__.__module__
    if module is None or module == str.__class__.__module__:
        return obj.__class__.__name__
    return module + "." + obj.__class__.__name__


def timestamp() -> int:
    return int(time())


def get_moscow_datetime():
    est_timezone = timezone(timedelta(hours=3))

    return datetime.now(est_timezone)


def get_moscow_date():
    return get_moscow_datetime().date()


def current_data_add(
        days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0
):
    return date.today() + timedelta(
        days=days,
        seconds=seconds,
        microseconds=microseconds,
        milliseconds=milliseconds,
        minutes=minutes,
        hours=hours,
        weeks=weeks,
    )


def get_logger(
    name: str | int,
    env: EnvType,
    job: str | uuid.UUID | int | None = None,
    filename: str = None,
    loki_handler: LokiHandler | None = None
) -> logging.Logger:
    formatter = jsonlogger.JsonFormatter(
        "{asctime}{levelname}{message}{env}",
        style="{",
        json_ensure_ascii=False,
        rename_fields={
            "asctime": "timestamp",
            "levelname": "level",
            "message": "msg",
        },
        static_fields={
            "env": env
        }
    )

    # Настройка логгера
    logger = logging.getLogger(f"custom_logger_{name}")
    logger.setLevel(logging.DEBUG)

    # Add filter with optional label - label will be included in tags if provided
    # logger.addFilter(TaggedLogFilter(job=job))

    # Создание обработчика (stdout)
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)

    if loki_handler:
        # Устанавливаем форматтер для LokiHandler, чтобы он отправлял JSON
        loki_handler.setFormatter(formatter)
        logger.addHandler(loki_handler)

    # all_handler = logging.FileHandler(filename="../logs/everything.txt", mode="a")
    # all_handler.setFormatter(formatter)
    # logger.addHandler(all_handler)

    # Создание обработчика (file out)
    if filename:
        fh = logging.FileHandler(filename=filename, mode="a")
        fh.setFormatter(formatter)
        logger.addHandler(fh)
    logger.addHandler(handler)

    return logger


def digits_only(v: str) -> str:
    if not re.fullmatch(r"\d+", v):
        raise ValueError("Must contain only digits")
    return v


def format_number(v: int) -> str:
    return f"{v:,}".replace(",", " ")


async def get_real_ip(proxy: str | None = None) -> tuple[ClientResponse, str]:
    async with aiohttp.ClientSession() as session:
        async with session.get("http://ip.8525.ru", proxy=proxy) as response:
            return response, (await response.text()).strip()
