"""
tests/shared.py
===============
Shared bootstrap for all VSS test modules.

Import this at the top of every test file BEFORE importing any vss.* code:

    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).resolve().parents[N]))  # reach vss/
    import shared  # or: from shared import make_state, make_mock_llm, ...

Provides:
- sys.path fix so  vss/  packages are importable without installation
- Rotating file + console logging to  tests/logs/vss_tests.log
- make_state()       — minimal VSSState dict factory
- make_mock_llm()    — MagicMock BaseLLMClient with AsyncMock generate/health
- make_sql_result()  — dict that mimics internal SQLAgent.run() return value
"""

from __future__ import annotations

import logging
import logging.handlers
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
from unittest.mock import AsyncMock, MagicMock

# ─────────────────────────────────────────────────────────────────────────────
# sys.path — make  vss/  importable from any working directory
# ─────────────────────────────────────────────────────────────────────────────

_VSS_ROOT = Path(__file__).resolve().parents[1]   # …/vss/
if str(_VSS_ROOT) not in sys.path:
    sys.path.insert(0, str(_VSS_ROOT))

# ─────────────────────────────────────────────────────────────────────────────
# Logging — shared rotating file at tests/logs/vss_tests.log
# ─────────────────────────────────────────────────────────────────────────────

LOGS_DIR = Path(__file__).resolve().parent / "logs"
LOGS_DIR.mkdir(parents=True, exist_ok=True)
LOG_FILE = LOGS_DIR / "vss_tests_2.log"

_log_configured = False

_W = 80   # visual line width


def setup_test_logging(level: int = logging.DEBUG) -> None:
    """
    Attach a rotating file handler and a console handler to the root logger.
    Safe to call multiple times — only configures once per process.
    """
    global _log_configured
    if _log_configured:
        return

    # File: full detail — timestamp, level, module, message
    file_fmt = logging.Formatter(
        "%(asctime)s  %(levelname)-8s  %(name)-40s  %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )
    # Console: compact — time + level + message only
    console_fmt = logging.Formatter(
        "%(asctime)s  %(levelname)-8s  %(name)s  %(message)s",
        datefmt="%H:%M:%S",
    )

    fh = logging.handlers.RotatingFileHandler(
        LOG_FILE,
        maxBytes=5 * 1024 * 1024,
        backupCount=5,
        encoding="utf-8",
    )
    fh.setFormatter(file_fmt)
    fh.setLevel(logging.DEBUG)

    ch = logging.StreamHandler(sys.stdout)
    ch.setFormatter(console_fmt)
    ch.setLevel(logging.INFO)

    root = logging.getLogger()
    root.setLevel(logging.DEBUG)

    if not any(isinstance(h, logging.handlers.RotatingFileHandler) for h in root.handlers):
        root.addHandler(fh)
    if not any(
        isinstance(h, logging.StreamHandler) and not isinstance(h, logging.FileHandler)
        for h in root.handlers
    ):
        root.addHandler(ch)

    ts = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
    root.info("═" * _W)
    root.info("  VSS TEST SESSION STARTED — %s", ts)
    root.info("  Log file: %s", LOG_FILE)
    root.info("═" * _W)

    _log_configured = True


# Configure immediately when this module is first imported
setup_test_logging()


# ─────────────────────────────────────────────────────────────────────────────
# Trace dump helper — call from any test to write state trace to log
# ─────────────────────────────────────────────────────────────────────────────

def log_state_trace(state: Dict[str, Any], context: str = "") -> None:
    """
    Write the VSSState trace list to the test log file in a readable block.

    Call this inside any test method after running a pipeline step.

    Example output in  vss_tests.log:
    ┌─ TRACE [test_sql_query_classified_as_sql] ────────────────────────────┐
    │  [14:23:01] State initialized: How many fire alerts yesterday?
    │  [14:23:01] Node: classify
    │  [14:23:01] Routing (rules): sql (0.90)
    │  [14:23:01] Node: sql
    │  intent=sql  conf=0.90  source=sql  status=completed
    └───────────────────────────────────────────────────────────────────────┘
    """
    log = logging.getLogger("vss.tests.trace")
    trace = state.get("trace", [])

    label  = f" TRACE [{context}] " if context else " TRACE "
    header = ("┌─" + label + "─" * (_W - len(label) - 3) + "┐")
    body   = [f"│  {entry}" for entry in trace]
    meta   = (
        f"│  intent={state.get('intent','?')}  "
        f"conf={state.get('intent_confidence', 0):.2f}  "
        f"source={state.get('response_source','?')}  "
        f"status={state.get('status','?')}"
    )
    footer = "└" + "─" * (_W - 1) + "┘"

    block = "\n".join(["", header] + body + [meta, footer])
    log.info(block)

# ─────────────────────────────────────────────────────────────────────────────
# State factory
# ─────────────────────────────────────────────────────────────────────────────


def make_state(
    query: str = "How many alerts yesterday?",
    *,
    intent: str = "sql",
    intent_confidence: float = 0.9,
    routing_reason: str = "test fixture",
    response_source: str = "sql",
    escalated: bool = False,
    escalation_reason: Optional[str] = None,
    sql_result: Optional[List[Dict]] = None,
    sql_result_formatted: str = "",
    sql_error: Optional[str] = None,
    vlm_response: str = "",
    uploaded_media: Optional[Dict] = None,
    status: str = "processing",
) -> Dict[str, Any]:
    """
    Return a fully-populated VSSState dict ready for testing.
    Calls the real create_state() so all required keys are present.
    """
    from orchestration.state import create_state

    state = create_state(query)
    state["intent"] = intent
    state["intent_confidence"] = intent_confidence
    state["routing_reason"] = routing_reason
    state["status"] = status
    state["response_source"] = response_source
    state["escalated"] = escalated
    state["escalation_reason"] = escalation_reason
    state["sql_result"] = sql_result if sql_result is not None else []
    state["sql_result_formatted"] = sql_result_formatted
    state["sql_error"] = sql_error
    state["vlm_response"] = vlm_response
    if uploaded_media:
        state["uploaded_media"] = uploaded_media
    return state


# ─────────────────────────────────────────────────────────────────────────────
# Mock factories
# ─────────────────────────────────────────────────────────────────────────────


def make_mock_llm(response: str = "SQL") -> MagicMock:
    """
    Return a MagicMock that looks like a BaseLLMClient.

    client.generate(...)  → coroutine returning `response`
    client.health_check() → coroutine returning True
    """
    client = MagicMock()
    client.generate = AsyncMock(return_value=response)
    client.health_check = AsyncMock(return_value=True)
    return client


def make_sql_result(
    *,
    final_answer: str = "There were 42 events.",
    execution_result: str = "[(42,)]",
    execution_error: str = "",
    sql_query: str = "SELECT count() FROM default.aggregated_analytics_final",
    sql_attempt: int = 1,
    extra_trace: Optional[List[str]] = None,
) -> Dict[str, Any]:
    """
    Return a dict that mirrors what SQLAgent.run() returns internally.
    Pass this as the return value of a mocked _get_agent().run().
    """
    return {
        "final_answer": final_answer,
        "execution_result": execution_result,
        "execution_error": execution_error,
        "sql_query": sql_query,
        "checked_sql_query": sql_query,
        "sql_attempt": sql_attempt,
        "trace": extra_trace or [],
    }


def make_completed_state(
    query: str = "How many alerts yesterday?",
    *,
    final_response: str = "There were 42 events.",
    intent: str = "sql",
    sql_query: str = "SELECT count() FROM default.aggregated_analytics_final",
    processing_time_ms: int = 100,
) -> Dict[str, Any]:
    """
    Return a VSSState that looks like it has completed the full pipeline.
    Used by API-level tests that mock VSSOrchestrator.run().
    """
    from orchestration.state import create_state, add_trace

    state = create_state(query)
    state["intent"] = intent
    state["intent_confidence"] = 0.9
    state["routing_reason"] = "SQL patterns: 3"
    state["status"] = "completed"
    state["response_source"] = "sql"
    state["sql_query"] = sql_query
    state["sql_result"] = [{"count": 42}]
    state["sql_result_formatted"] = final_response
    state["sql_error"] = None
    state["escalated"] = False
    state["final_response"] = final_response
    state["processing_time_ms"] = processing_time_ms
    add_trace(state, "mock pipeline: completed")
    return state
