"""Logging helpers for compact terminal output."""

from __future__ import annotations

import logging
from typing import Final

from porki.constants import COLOR_RESET, LOG_LEVEL_COLORS


class EventContextFilter(logging.Filter):
    """Populate structured event fields so every log line is parseable."""

    DEFAULTS: Final[dict[str, str]] = {
        "evt": "GEN",
        "goal": "-",
        "role": "-",
        "task": "-",
        "state": "-",
        "next_retry": "-",
    }

    def filter(self, record: logging.LogRecord) -> bool:
        """Ensure all structured keys exist on the record."""
        for key, value in self.DEFAULTS.items():
            if not hasattr(record, key):
                setattr(record, key, value)
        return True


class EventFormatter(logging.Formatter):
    """Append normalized structured event context to each formatted line."""

    _ORDERED_KEYS: Final[tuple[str, ...]] = ("evt", "goal", "role", "task", "state", "next_retry")

    def format(self, record: logging.LogRecord) -> str:
        """Format base message and append key-value context suffix."""
        base = super().format(record)
        suffix = " ".join(f"{key}={getattr(record, key, '-')}" for key in self._ORDERED_KEYS)
        return f"{base} | {suffix}"


class ConciseEventFormatter(logging.Formatter):
    """Human-first formatter that omits empty/default structured fields."""

    def format(self, record: logging.LogRecord) -> str:
        """Format message with compact optional context suffix."""
        base = super().format(record)
        evt = getattr(record, "evt", "GEN")
        goal = getattr(record, "goal", "-")
        role = getattr(record, "role", "-")
        task = getattr(record, "task", "-")
        state = getattr(record, "state", "-")
        next_retry = getattr(record, "next_retry", "-")

        parts: list[str] = []
        if evt != "GEN":
            parts.append(f"evt={evt}")
        if role != "-":
            parts.append(f"role={role}")
        if task != "-":
            parts.append(f"task={task}")
        if state != "-":
            parts.append(f"state={state}")
        if goal != "-":
            parts.append(f"goal={goal}")
        if next_retry != "-":
            parts.append(f"next={next_retry}")

        if not parts:
            return base
        return f"{base} | {' '.join(parts)}"


class CompactingHandler(logging.Handler):
    """Collapse consecutive duplicate log messages into one counted line."""

    _SUMMARY_PREFIX: Final[str] = "+"

    def __init__(self, delegate: logging.Handler):
        """Wrap a concrete handler that performs the final output."""
        super().__init__(level=delegate.level)
        self.delegate = delegate
        self._pending_record: logging.LogRecord | None = None
        self._pending_message: str | None = None
        self._pending_count = 0

    def emit(self, record: logging.LogRecord) -> None:
        """Buffer and compact adjacent duplicate message bodies."""
        try:
            message = record.getMessage()
            self.acquire()
            if record.levelno >= logging.WARNING:
                self._emit_pending()
                self.delegate.handle(record)
                return
            if self._pending_record is None:
                self._pending_record = record
                self._pending_message = message
                self._pending_count = 1
                return
            if message == self._pending_message:
                self._pending_count += 1
                return
            self._emit_pending()
            self._pending_record = record
            self._pending_message = message
            self._pending_count = 1
        finally:
            self.release()

    def flush(self) -> None:
        """Flush any buffered compacted record and the delegate handler."""
        try:
            self.acquire()
            self._emit_pending()
            self.delegate.flush()
        finally:
            self.release()

    def close(self) -> None:
        """Flush buffered record before closing delegate."""
        try:
            self.flush()
        finally:
            self.delegate.close()
            super().close()

    def _emit_pending(self) -> None:
        """Emit the current pending record, compacted when repeated."""
        if self._pending_record is None:
            return
        if self._pending_count <= 1:
            self.delegate.handle(self._pending_record)
        else:
            summary_record = self._clone_record_with_message(
                self._pending_record,
                f"{self._SUMMARY_PREFIX}{self._pending_count} {self._pending_message}",
            )
            self.delegate.handle(summary_record)
        self._pending_record = None
        self._pending_message = None
        self._pending_count = 0

    @staticmethod
    def _clone_record_with_message(record: logging.LogRecord, message: str) -> logging.LogRecord:
        """Create a record copy that preserves metadata but overrides message text."""
        clone = logging.LogRecord(
            name=record.name,
            level=record.levelno,
            pathname=record.pathname,
            lineno=record.lineno,
            msg=message,
            args=(),
            exc_info=record.exc_info,
            func=record.funcName,
            sinfo=record.stack_info,
        )
        clone.created = record.created
        clone.msecs = record.msecs
        clone.relativeCreated = record.relativeCreated
        clone.thread = record.thread
        clone.threadName = record.threadName
        clone.processName = record.processName
        clone.process = record.process
        standard = set(clone.__dict__.keys())
        for key, value in record.__dict__.items():
            if key not in standard:
                setattr(clone, key, value)
        return clone


class ColoredEventFormatter(EventFormatter):
    """Colored version of EventFormatter that applies ANSI colors based on log level."""

    def format(self, record: logging.LogRecord) -> str:
        """Format base message with color applied to log level."""
        original_levelname = record.levelname

        color = LOG_LEVEL_COLORS.get(record.levelno, "")
        if color:
            record.levelname = f"{color}{record.levelname}{COLOR_RESET}"

        formatted = super().format(record)

        record.levelname = original_levelname

        return formatted


class ColoredConciseEventFormatter(ConciseEventFormatter):
    """Colored version of concise formatter for terminal readability."""

    def format(self, record: logging.LogRecord) -> str:
        """Format base message with color applied to log level."""
        original_levelname = record.levelname

        color = LOG_LEVEL_COLORS.get(record.levelno, "")
        if color:
            record.levelname = f"{color}{record.levelname}{COLOR_RESET}"

        formatted = super().format(record)

        record.levelname = original_levelname

        return formatted
