"""Trendline widget with historical data tracking."""

from __future__ import annotations

from collections import deque
from typing import Any

from rich.text import Text

from hil_testbench.display.widgets.base import RenderOutput, WidgetContext
from hil_testbench.display.widgets.theme import get_theme


class TrendlineData:
    """Stores historical parameter values for trend analysis."""

    def __init__(self, maxlen: int = 10):
        """
        Args:
            maxlen: Maximum number of historical samples to retain
        """
        self.history: deque[tuple[float, float]] = deque(maxlen=maxlen)
        # (timestamp, value) pairs

    def add(self, timestamp: float, value: float):
        """Add new sample to history."""
        self.history.append((timestamp, value))

    def get_current_value(self) -> float | None:
        """Get most recent value."""
        return self.history[-1][1] if self.history else None

    def calculate_slope(self, window: int = 3) -> float:
        """Calculate trend slope over last N samples."""
        if len(self.history) < 2:
            return 0.0

        recent = list(self.history)[-window:]
        if len(recent) < 2:
            return 0.0

        time_delta = recent[-1][0] - recent[0][0]
        if time_delta == 0:
            return 0.0

        value_delta = recent[-1][1] - recent[0][1]
        return value_delta / time_delta

    def get_arrow(self, threshold: float = 0.1) -> str:
        """Get trend arrow based on slope."""
        slope = self.calculate_slope()
        theme = get_theme()

        # Normalize slope to percentage change
        current = self.get_current_value()
        if current and current != 0:
            slope_pct = abs(slope) / abs(current)
        else:
            slope_pct = abs(slope)

        if slope > 0:
            if slope_pct > threshold * 2:
                return theme.arrows["up_steep"]
            elif slope_pct > threshold / 2:
                return theme.arrows["up_gradual"]
        elif slope < 0:
            if slope_pct > threshold * 2:
                return theme.arrows["down_steep"]
            elif slope_pct > threshold / 2:
                return theme.arrows["down_gradual"]

        return theme.arrows["flat"]

    def get_bars(self, normalize_range: tuple[float, float] | None = None) -> str:
        """Render history as vertical bar chart."""
        if not self.history:
            return ""

        theme = get_theme()
        values = [v for _, v in self.history]

        # Determine normalization range
        if normalize_range:
            min_val, max_val = normalize_range
        else:
            min_val, max_val = min(values), max(values)

        # Avoid division by zero
        if max_val == min_val:
            min_val, max_val = min_val - 1, min_val + 1

        # Map each value to bar character
        bars = []
        num_levels = len(theme.bar_chars)
        for value in values:
            normalized = (value - min_val) / (max_val - min_val)
            level = int(normalized * (num_levels - 1))
            level = max(0, min(level, num_levels - 1))
            bars.append(theme.bar_chars[level])

        return "".join(bars)


class TrendlineWidget:
    """Compact trendline with bars and directional arrow."""

    def __init__(
        self,
        data: TrendlineData,
        thresholds: dict[str, Any] | None = None,
        normalize_range: tuple[float, float] | None = None,
        show_arrow: bool = True,
    ):
        """
        Args:
            data: Trendline historical data
            thresholds: Threshold dict for color coding
            normalize_range: (min, max) for bar scaling
            show_arrow: Whether to show trend arrow
        """
        self.data = data
        self.thresholds = thresholds or {}
        self.normalize_range = normalize_range
        self.show_arrow = show_arrow

    def _get_color(self, value: float, slope: float) -> str:
        """Determine color based on value + trend direction."""
        theme = get_theme()

        # TODO: Implement threshold-aware color logic
        # For now, simple logic based on trend direction
        if slope > 0.1:
            return theme.threshold_colors["good"]
        elif slope < -0.1:
            return theme.threshold_colors["bad"]
        else:
            return theme.threshold_colors["neutral"]

    def render(self, context: WidgetContext) -> RenderOutput:
        """Render trendline with bars and arrow."""
        if context.is_minimal():
            # Don't show trendline in minimal mode
            return RenderOutput.from_text(Text(""))

        bars = self.data.get_bars(self.normalize_range)
        if not bars:
            return RenderOutput.from_text(Text(""))

        current_value = self.data.get_current_value()
        if current_value is None:
            return RenderOutput.from_text(Text(""))

        slope = self.data.calculate_slope()
        color = self._get_color(current_value, slope)

        text = Text(bars, style=color)

        if self.show_arrow:
            arrow = self.data.get_arrow()
            text.append(f" {arrow}", style=color)

        return RenderOutput.from_text(text)
