"""
Output Guardrail Executor for Mid Platform.
[AC-MARH-01, AC-MARH-02] Output guardrail enforcement before returning segments.

Features:
- Mandatory output filtering before segments are returned
- Guardrail trigger logging with rule_id
- Integration with existing OutputFilter
"""

import logging
from dataclasses import dataclass
from typing import Any

from app.models.entities import GuardrailResult
from app.services.guardrail.output_filter import OutputFilter
from app.services.guardrail.word_service import ForbiddenWordService

logger = logging.getLogger(__name__)


@dataclass
class GuardrailExecutionResult:
    """Result of guardrail execution."""
    filtered_text: str
    triggered: bool = False
    blocked: bool = False
    rule_id: str | None = None
    triggered_words: list[str] | None = None
    triggered_categories: list[str] | None = None


class OutputGuardrailExecutor:
    """
    [AC-MARH-01, AC-MARH-02] Output guardrail executor for mandatory filtering.

    This component enforces output guardrail filtering before any segments
    are returned to the client. It wraps the existing OutputFilter and adds
    trace/logging capabilities required by MARH.
    """

    def __init__(
        self,
        output_filter: OutputFilter | None = None,
        word_service: ForbiddenWordService | None = None,
    ):
        if output_filter:
            self._output_filter = output_filter
        elif word_service:
            self._output_filter = OutputFilter(word_service)
        else:
            self._output_filter = None

    async def execute(
        self,
        text: str,
        tenant_id: str,
    ) -> GuardrailExecutionResult:
        """
        [AC-MARH-01] Execute guardrail filtering on output text.

        Args:
            text: The text to filter
            tenant_id: Tenant ID for isolation

        Returns:
            GuardrailExecutionResult with filtered text and trigger info
        """
        if not text or not text.strip():
            return GuardrailExecutionResult(filtered_text=text)

        if not self._output_filter:
            logger.debug("[AC-MARH-01] No output filter configured, skipping guardrail")
            return GuardrailExecutionResult(filtered_text=text)

        try:
            result: GuardrailResult = await self._output_filter.filter(text, tenant_id)

            triggered = bool(result.triggered_words)
            rule_id = None
            if triggered and result.triggered_categories:
                rule_id = f"forbidden_word:{','.join(result.triggered_categories[:3])}"

            if triggered:
                logger.info(
                    f"[AC-MARH-02] Guardrail triggered: tenant={tenant_id}, "
                    f"blocked={result.blocked}, rule_id={rule_id}, "
                    f"words={result.triggered_words}"
                )

            return GuardrailExecutionResult(
                filtered_text=result.reply,
                triggered=triggered,
                blocked=result.blocked,
                rule_id=rule_id,
                triggered_words=result.triggered_words,
                triggered_categories=result.triggered_categories,
            )

        except Exception as e:
            logger.error(f"[AC-MARH-01] Guardrail execution failed: {e}")
            return GuardrailExecutionResult(
                filtered_text=text,
                triggered=False,
                rule_id=f"error:{str(e)[:50]}",
            )

    async def filter_segments(
        self,
        segments: list[Any],
        tenant_id: str,
    ) -> tuple[list[Any], GuardrailExecutionResult]:
        """
        [AC-MARH-01] Filter all segments and return combined result.

        Args:
            segments: List of Segment objects with text field
            tenant_id: Tenant ID for isolation

        Returns:
            Tuple of (filtered_segments, combined_result)
        """
        if not segments:
            return segments, GuardrailExecutionResult(filtered_text="")

        if not self._output_filter:
            return segments, GuardrailExecutionResult(filtered_text="")

        combined_text = "\n\n".join(s.text for s in segments)
        result = await self.execute(combined_text, tenant_id)

        if result.blocked:
            from app.models.mid.schemas import Segment
            return [
                Segment(text=result.filtered_text, delay_after=0)
            ], result

        if result.triggered:
            filtered_paragraphs = result.filtered_text.split("\n\n")
            filtered_segments = []
            for i, para in enumerate(filtered_paragraphs):
                if para.strip():
                    from app.models.mid.schemas import Segment
                    filtered_segments.append(
                        Segment(
                            text=para.strip(),
                            delay_after=segments[0].delay_after if segments and i < len(segments) else 0,
                        )
                    )
            return filtered_segments, result

        return segments, result
