"""Keyword position tracking with state persistence and alert detection."""

from __future__ import annotations

import json
import logging
from pathlib import Path

from src.config.settings import PROJECT_ROOT
from src.models.data_models import KeywordPosition

logger = logging.getLogger("seo_optimizer")

STATE_FILE = PROJECT_ROOT / "keyword_state.json"


def extract_keyword_positions(
    query_rows: list[dict],
    tracked_keywords: list[str],
) -> list[KeywordPosition]:
    """Extract positions for tracked keywords from query API rows.

    Args:
        query_rows: Raw API rows with 'query' dimension.
        tracked_keywords: List of keywords to track.

    Returns:
        List of KeywordPosition (without previous/change data).
    """
    # Build lookup: lowercase query -> row
    query_lookup: dict[str, dict] = {}
    for row in query_rows:
        keys = row.get("keys", [])
        if keys:
            query_lookup[keys[0].lower()] = row

    positions = []
    for keyword in tracked_keywords:
        row = query_lookup.get(keyword.lower())
        if row:
            positions.append(
                KeywordPosition(
                    keyword=keyword,
                    current_position=round(row.get("position", 0), 2),
                    clicks=row.get("clicks", 0),
                    impressions=row.get("impressions", 0),
                )
            )
        else:
            positions.append(
                KeywordPosition(
                    keyword=keyword,
                    current_position=0.0,
                )
            )
            logger.debug("Keyword '%s' not found in search data", keyword)

    return positions


def load_previous_state(site_url: str) -> dict[str, float]:
    """Load previous keyword positions from state file.

    Returns:
        Dict of keyword -> previous position.
    """
    if not STATE_FILE.exists():
        return {}

    try:
        with open(STATE_FILE, "r", encoding="utf-8") as f:
            state = json.load(f)
        return state.get(site_url, {})
    except (json.JSONDecodeError, OSError) as e:
        logger.warning("Failed to load keyword state: %s", e)
        return {}


def save_current_state(site_url: str, positions: list[KeywordPosition]) -> None:
    """Save current keyword positions to state file."""
    state = {}
    if STATE_FILE.exists():
        try:
            with open(STATE_FILE, "r", encoding="utf-8") as f:
                state = json.load(f)
        except (json.JSONDecodeError, OSError):
            state = {}

    state[site_url] = {
        kp.keyword: kp.current_position
        for kp in positions
        if kp.current_position > 0
    }

    with open(STATE_FILE, "w", encoding="utf-8") as f:
        json.dump(state, f, ensure_ascii=False, indent=2)

    logger.debug("Saved keyword state for %s", site_url)


def track_keywords(
    query_rows: list[dict],
    tracked_keywords: list[str],
    site_url: str,
    alert_threshold: int = 3,
) -> list[KeywordPosition]:
    """Full keyword tracking: extract, compare with previous, detect alerts.

    Args:
        query_rows: Raw API rows with 'query' dimension.
        tracked_keywords: Keywords to track.
        site_url: Site URL for state file key.
        alert_threshold: Position change threshold for alerts.

    Returns:
        List of KeywordPosition with previous/change/alert data.
    """
    positions = extract_keyword_positions(query_rows, tracked_keywords)
    previous = load_previous_state(site_url)

    for kp in positions:
        prev_pos = previous.get(kp.keyword, 0.0)
        kp.previous_position = prev_pos

        if kp.current_position > 0 and prev_pos > 0:
            kp.change = round(kp.current_position - prev_pos, 2)
            kp.is_alert = abs(kp.change) >= alert_threshold
        elif prev_pos > 0 and kp.current_position == 0:
            # Keyword disappeared from results
            kp.change = 0.0
            kp.is_alert = True

        if kp.is_alert:
            logger.warning(
                "Keyword alert [%s]: '%s' position %.1f → %.1f (change: %+.1f)",
                site_url, kp.keyword, prev_pos, kp.current_position, kp.change,
            )

    save_current_state(site_url, positions)

    return positions
