"""Price Tracker plugin — store, compare, and alert on price changes."""

from __future__ import annotations

import time
from typing import Any

from agent_scout.db.database import Database
from agent_scout.db.models import PriceSnapshot
from agent_scout.events import Event, EventBus, EventType
from agent_scout.plugins.base import Plugin, PluginConfig, PluginParam, ToolSpec


class PriceTrackerPlugin(Plugin):
    """Track prices across sources, detect drops, and compare items.

    Stores price snapshots in the SQLite `price_history` table and
    provides tools for querying history, comparing, and setting alerts.
    """

    def __init__(
        self,
        config: PluginConfig | None = None,
        db: Database | None = None,
        event_bus: EventBus | None = None,
    ) -> None:
        super().__init__(config)
        self._db = db
        self._bus = event_bus

    @property
    def name(self) -> str:
        return "price_tracker"

    @property
    def description(self) -> str:
        return "Track and compare prices across sources with alerts"

    def get_tools(self) -> list[ToolSpec]:
        return [
            ToolSpec(
                name="track_price",
                description="Record a price snapshot for an item from a source.",
                parameters=[
                    PluginParam(name="item_name", description="Name of the item", required=True),
                    PluginParam(
                        name="price",
                        description="Current price",
                        param_type="number",
                        required=True,
                    ),
                    PluginParam(name="currency", description="Currency code", default="USD"),
                    PluginParam(
                        name="source",
                        description="Where the price was found",
                        required=True,
                    ),
                    PluginParam(name="url", description="URL of the listing"),
                ],
            ),
            ToolSpec(
                name="get_price_history",
                description="Get price history for an item. Returns chronological price snapshots.",
                parameters=[
                    PluginParam(name="item_name", description="Name of the item", required=True),
                    PluginParam(
                        name="limit",
                        description="Max number of entries",
                        param_type="number",
                        default=20,
                    ),
                ],
            ),
            ToolSpec(
                name="compare_prices",
                description="Compare current prices for an item across all tracked sources.",
                parameters=[
                    PluginParam(name="item_name", description="Name of the item", required=True),
                ],
            ),
            ToolSpec(
                name="check_price_drop",
                description="Check if a price has dropped below a threshold for an item.",
                parameters=[
                    PluginParam(name="item_name", description="Name of the item", required=True),
                    PluginParam(
                        name="threshold",
                        description="Price threshold to check against",
                        param_type="number",
                        required=True,
                    ),
                ],
            ),
        ]

    async def execute(self, tool_name: str, tool_input: dict[str, Any]) -> str:
        if tool_name == "track_price":
            return await self._track_price(tool_input)
        elif tool_name == "get_price_history":
            return await self._get_price_history(tool_input)
        elif tool_name == "compare_prices":
            return await self._compare_prices(tool_input)
        elif tool_name == "check_price_drop":
            return await self._check_price_drop(tool_input)
        return f"Unknown tool: {tool_name}"

    async def _track_price(self, tool_input: dict[str, Any]) -> str:
        if not self._db:
            return "Error: Database not available"

        item_name = tool_input.get("item_name", "")
        price = float(tool_input.get("price", 0))
        currency = tool_input.get("currency", "USD")
        source = tool_input.get("source", "")
        url = tool_input.get("url", "")

        if not item_name or not source:
            return "Error: item_name and source are required"

        snapshot = PriceSnapshot(
            item_name=item_name,
            price=price,
            currency=currency,
            source=source,
            url=url,
        )
        await self._db.store_price(snapshot)

        if self._bus:
            await self._bus.emit(
                Event(
                    event_type=EventType.COST_UPDATE,
                    data={
                        "item_name": item_name,
                        "price": price,
                        "currency": currency,
                        "source": source,
                    },
                )
            )

        return f"Tracked: {item_name} at {currency} {price:.2f} from {source}"

    async def _get_price_history(self, tool_input: dict[str, Any]) -> str:
        if not self._db:
            return "Error: Database not available"

        item_name = tool_input.get("item_name", "")
        limit = int(tool_input.get("limit", 20))

        if not item_name:
            return "Error: item_name is required"

        history = await self._db.get_price_history(item_name, limit=limit)
        if not history:
            return f"No price history found for '{item_name}'"

        lines = [f"Price history for '{item_name}' ({len(history)} entries):"]
        for snap in history:
            ts = time.strftime("%Y-%m-%d %H:%M", time.localtime(snap.captured_at))
            lines.append(f"  {ts} | {snap.currency} {snap.price:.2f} | {snap.source}")

        return "\n".join(lines)

    async def _compare_prices(self, tool_input: dict[str, Any]) -> str:
        if not self._db:
            return "Error: Database not available"

        item_name = tool_input.get("item_name", "")
        if not item_name:
            return "Error: item_name is required"

        history = await self._db.get_price_history(item_name, limit=100)
        if not history:
            return f"No price data found for '{item_name}'"

        # Get latest price per source
        latest_by_source: dict[str, PriceSnapshot] = {}
        for snap in history:
            if snap.source not in latest_by_source:
                latest_by_source[snap.source] = snap

        if not latest_by_source:
            return f"No prices to compare for '{item_name}'"

        # Sort by price ascending
        sorted_sources = sorted(latest_by_source.values(), key=lambda s: s.price)

        lines = [f"Price comparison for '{item_name}':"]
        for i, snap in enumerate(sorted_sources, 1):
            marker = " <- BEST" if i == 1 else ""
            lines.append(f"  {i}. {snap.source}: {snap.currency} {snap.price:.2f}{marker}")
            if snap.url:
                lines.append(f"     {snap.url}")

        if len(sorted_sources) > 1:
            diff = sorted_sources[-1].price - sorted_sources[0].price
            cur = sorted_sources[0].currency
            lines.append(f"\nSavings: {cur} {diff:.2f} by choosing the best option")

        return "\n".join(lines)

    async def _check_price_drop(self, tool_input: dict[str, Any]) -> str:
        if not self._db:
            return "Error: Database not available"

        item_name = tool_input.get("item_name", "")
        threshold = float(tool_input.get("threshold", 0))

        if not item_name:
            return "Error: item_name is required"

        history = await self._db.get_price_history(item_name, limit=1)
        if not history:
            return f"No price data found for '{item_name}'"

        latest = history[0]
        if latest.price <= threshold:
            msg = (
                f"ALERT: '{item_name}' is at {latest.currency} {latest.price:.2f} "
                f"(below threshold of {latest.currency} {threshold:.2f}) from {latest.source}"
            )
            if self._bus:
                await self._bus.emit(
                    Event(
                        event_type=EventType.BUDGET_WARNING,
                        data={
                            "item_name": item_name,
                            "price": latest.price,
                            "threshold": threshold,
                            "source": latest.source,
                        },
                    )
                )
            return msg

        return (
            f"'{item_name}' is at {latest.currency} {latest.price:.2f} "
            f"(above threshold of {latest.currency} {threshold:.2f})"
        )
