"""Data transformation for API responses."""
import json
from datetime import datetime
from typing import Optional

from .. import db
from ..config import (
    get_player_name,
    get_display_columns,
    set_display_columns,
    AVAILABLE_COLUMNS,
    load_config,
    save_config,
    clear_config_cache,
)
from ..ui import calculate_summary


def get_mmr_history(
    limit: int = 100,
    days: Optional[int] = None,
    matchup: Optional[str] = None,
    result: Optional[str] = None,
    player_race: Optional[str] = None,
    is_ladder: Optional[bool] = True,
    region: Optional[str] = None,
) -> dict:
    """Get MMR history for graphing."""
    replays = db.get_replays(
        limit=limit,
        days=days,
        matchup=matchup,
        result=result,
        player_race=player_race,
        is_ladder=is_ladder,
        region=region,
    )
    data = [
        {
            "date": r["played_at"],
            "mmr": r["player_mmr"],
            "result": r["result"],
            "matchup": r["matchup"],
        }
        for r in reversed(replays)  # Oldest first for graph
        if r.get("player_mmr")
    ]

    tags = _format_tags(db.get_tags())

    return {
        "player_name": get_player_name(),
        "data": data,
        "tags": tags,
    }


def get_replays_api(
    matchup: Optional[str] = None,
    result: Optional[str] = None,
    map_name: Optional[str] = None,
    days: Optional[int] = None,
    limit: Optional[int] = None,
    min_length: Optional[int] = None,
    max_length: Optional[int] = None,
    min_workers_8m: Optional[int] = None,
    max_workers_8m: Optional[int] = None,
    player_race: Optional[str] = None,
    is_ladder: Optional[bool] = None,
    region: Optional[str] = None,
) -> dict:
    """Get replays with optional filters, plus summary stats."""
    replays = db.get_replays(
        matchup=matchup,
        result=result,
        map_name=map_name,
        days=days,
        limit=limit,
        min_length=min_length,
        max_length=max_length,
        min_workers_8m=min_workers_8m,
        max_workers_8m=max_workers_8m,
        player_race=player_race,
        is_ladder=is_ladder,
        region=region,
    )

    _enrich_mmr_changes(replays)
    summary = calculate_summary(replays)

    return {
        "replays": replays,
        "summary": summary,
        "total": len(replays),
    }


def get_latest_api() -> dict:
    """Get the most recent replay."""
    replay = db.get_latest_replay()
    return {"replay": replay}


def get_stats_api(
    matchup: Optional[str] = None,
    days: Optional[int] = None,
    player_race: Optional[str] = None,
    is_ladder: Optional[bool] = None,
    region: Optional[str] = None,
) -> dict:
    """Get aggregate stats and per-matchup breakdown."""
    stats = db.get_stats(
        matchup=matchup, days=days,
        player_race=player_race, is_ladder=is_ladder, region=region,
    )
    matchup_stats = db.get_stats_by_matchup(
        days=days, player_race=player_race, is_ladder=is_ladder, region=region,
    ) if not matchup else []

    return {
        "stats": stats,
        "matchup_stats": matchup_stats,
    }


def get_maps_api() -> dict:
    """Get unique map names."""
    maps = db.get_unique_map_names()
    return {"maps": maps}


def get_tags_api() -> dict:
    """Get all tags with type classification."""
    tags = _format_tags(db.get_tags())
    return {"tags": tags}


def create_tag_api(label: str, date: Optional[str] = None, end_date: Optional[str] = None) -> dict:
    """Create a new tag."""
    tag_date = date or datetime.now().strftime("%Y-%m-%d")
    success = db.add_tag(tag_date, label, end_date=end_date)

    if success:
        return {"success": True, "message": f"Tag '{label}' created"}
    return {"success": False, "message": f"Tag already exists: {label} on {tag_date}"}


def end_tag_api(tag_id: int, end_date: Optional[str] = None) -> dict:
    """End an ongoing tag by finding it by ID."""
    date = end_date or datetime.now().strftime("%Y-%m-%d")

    all_tags = db.get_tags()
    tag = next((t for t in all_tags if t["id"] == tag_id), None)

    if not tag:
        return {"success": False, "message": f"Tag not found: {tag_id}"}

    success = db.end_tag(tag["label"], date)
    if success:
        return {"success": True, "message": f"Tag '{tag['label']}' ended on {date}"}
    return {"success": False, "message": f"No ongoing tag found: {tag['label']}"}


def delete_tag_api(tag_id: int) -> dict:
    """Delete a tag by ID."""
    all_tags = db.get_tags()
    tag = next((t for t in all_tags if t["id"] == tag_id), None)

    if not tag:
        return {"success": False, "message": f"Tag not found: {tag_id}"}

    count = db.remove_tag(tag["tag_date"], tag["label"])
    if count > 0:
        return {"success": True, "message": f"Tag '{tag['label']}' deleted"}
    return {"success": False, "message": f"Failed to delete tag: {tag_id}"}


def get_columns_api() -> dict:
    """Get current display columns and available columns."""
    current = get_display_columns()
    available = {
        key: {"header": header, "width": width, "justify": justify}
        for key, (header, width, justify) in AVAILABLE_COLUMNS.items()
    }

    return {
        "current": current,
        "available": available,
    }


def update_columns_api(columns: list) -> dict:
    """Update display columns."""
    invalid = [c for c in columns if c not in AVAILABLE_COLUMNS]
    if invalid:
        return {"success": False, "message": f"Invalid columns: {', '.join(invalid)}"}

    set_display_columns(columns)
    return {"success": True, "columns": columns}


def trigger_scan_api() -> dict:
    """Trigger a replay scan."""
    from ..cli import auto_scan

    new_count = auto_scan(silent=True)
    return {"new_replays": new_count}


def get_config_api() -> dict:
    """Get current configuration info."""
    config = load_config()

    return {
        "player_name": config["player_name"],
        "region": config.get("region", ""),
        "benchmarks": config["benchmarks"],
        "server": config["server"],
        "auto_scan_interval_ms": config.get("auto_scan_interval_ms", 2000),
        "blizzard_configured": bool(
            config.get("blizzard", {}).get("client_id")
            and config.get("blizzard", {}).get("client_secret")
        ),
    }


def get_ranked_mmr_api() -> dict:
    """Get current ranked MMR per race from Blizzard API."""
    from ..blizzard_api import fetch_ranked_mmr, is_configured

    if not is_configured():
        return {"configured": False, "mmr": {}}

    mmr_data = fetch_ranked_mmr()
    return {"configured": True, "mmr": mmr_data}


def update_config_api(
    player_name: Optional[str] = None,
    region: Optional[str] = None,
    blizzard_client_id: Optional[str] = None,
    blizzard_client_secret: Optional[str] = None,
) -> dict:
    """Update configuration."""
    config = load_config()

    if player_name is not None:
        config["player_name"] = player_name
    if region is not None:
        config["region"] = region
    if blizzard_client_id is not None or blizzard_client_secret is not None:
        if "blizzard" not in config:
            config["blizzard"] = {}
        if blizzard_client_id is not None:
            config["blizzard"]["client_id"] = blizzard_client_id
        if blizzard_client_secret is not None:
            config["blizzard"]["client_secret"] = blizzard_client_secret

    save_config(config)
    clear_config_cache()
    return {"success": True}


def get_races_api() -> dict:
    """Get race distribution and auto-detected default race."""
    distribution = db.get_race_distribution()
    default_race = db.get_most_played_race()

    return {
        "races": distribution,
        "default": default_race,
    }


def get_regions_api() -> dict:
    """Get region distribution and auto-detected default region."""
    distribution = db.get_region_distribution()
    default_region = db.get_most_played_region()

    return {
        "regions": distribution,
        "default": default_region,
    }


# ============================================================
# REPLAY NOTES
# ============================================================


def get_notes_api(replay_id: str) -> dict:
    """Get analysis notes for a replay."""
    notes = db.get_replay_notes(replay_id)
    if notes and notes.get("analysis_json"):
        notes["analysis"] = json.loads(notes["analysis_json"])
    return {"notes": notes}


def save_notes_api(replay_id: str, analysis: dict) -> dict:
    """Save analysis notes for a replay."""
    analysis_json = json.dumps(analysis)
    success = db.save_replay_notes(replay_id, analysis_json)
    if success:
        return {"success": True, "message": "Analysis saved"}
    return {"success": False, "message": "Failed to save analysis"}


def delete_notes_api(replay_id: str) -> dict:
    """Delete analysis notes for a replay."""
    success = db.delete_replay_notes(replay_id)
    if success:
        return {"success": True, "message": "Analysis deleted"}
    return {"success": False, "message": "No analysis found"}


def get_notes_feed_api(days: Optional[int] = None, limit: Optional[int] = None) -> dict:
    """Get all notes with replay context for feed view."""
    notes = db.get_all_notes(days=days, limit=limit)
    # Parse JSON for each note
    for note in notes:
        if note.get("analysis_json"):
            note["analysis"] = json.loads(note["analysis_json"])
    return {"notes": notes}


def ignore_replay_api(replay_id: str) -> dict:
    """Mark a replay as ignored."""
    success = db.set_replay_ignored(replay_id, True)
    if success:
        return {"success": True, "message": "Replay ignored"}
    return {"success": False, "message": "Replay not found"}


def unignore_replay_api(replay_id: str) -> dict:
    """Remove ignored flag from a replay."""
    success = db.set_replay_ignored(replay_id, False)
    if success:
        return {"success": True, "message": "Replay restored"}
    return {"success": False, "message": "Replay not found"}


def get_ignored_replays_api() -> dict:
    """Get all ignored replays."""
    replays = db.get_ignored_replays()
    return {"replays": replays, "total": len(replays)}


def get_analysis_config_api() -> dict:
    """Get post-game analysis form field configuration."""
    config = load_config()
    fields = config.get("post_game_analysis", {}).get("fields", [])
    return {"fields": fields}


# ============================================================
# LIVE ANALYSIS DRAFT (in-memory, ephemeral)
# ============================================================

# Stores the current draft being typed in the GUI
_live_draft = {"active": False, "replay": None, "analysis": {}}


def set_draft_api(replay: dict, analysis: dict) -> dict:
    """Set the current live draft (called as user types)."""
    global _live_draft
    _live_draft = {"active": True, "replay": replay, "analysis": analysis}
    return {"success": True}


def get_draft_api() -> dict:
    """Get the current live draft (polled by widget)."""
    return dict(_live_draft)


def clear_draft_api() -> dict:
    """Clear the live draft (called when form closes)."""
    global _live_draft
    _live_draft = {"active": False, "replay": None, "analysis": {}}
    return {"success": True}


# ============================================================
# INTERNAL HELPERS
# ============================================================


def _enrich_mmr_changes(replays: list):
    """Add post_mmr and mmr_change fields to each replay.

    Post-game MMR = next same-race game's starting MMR.
    For the most recent game per race, uses Blizzard API current MMR if available.
    MMR change = post_mmr - player_mmr.

    Modifies replays in-place (they're ordered newest first).
    """
    # Try to get current ranked MMR from Blizzard API for the latest games
    current_mmr_by_race = {}
    try:
        from ..blizzard_api import fetch_ranked_mmr, is_configured
        if is_configured():
            api_mmr = fetch_ranked_mmr()
            for race, data in api_mmr.items():
                if data.get("mmr"):
                    current_mmr_by_race[race] = data["mmr"]
    except Exception:
        pass

    # Track the next game's MMR for each race (iterating newest→oldest)
    next_mmr_by_race = {}

    for replay in replays:
        race = replay.get("player_race")
        mmr = replay.get("player_mmr")

        if race and mmr is not None:
            if race in next_mmr_by_race:
                replay["post_mmr"] = next_mmr_by_race[race]
                replay["mmr_change"] = next_mmr_by_race[race] - mmr
            elif race in current_mmr_by_race:
                # Most recent game - use Blizzard API current MMR
                replay["post_mmr"] = current_mmr_by_race[race]
                replay["mmr_change"] = current_mmr_by_race[race] - mmr
            else:
                replay["post_mmr"] = mmr
                replay["mmr_change"] = None

            next_mmr_by_race[race] = mmr
        else:
            replay["post_mmr"] = None
            replay["mmr_change"] = None


def _format_tags(raw_tags: list) -> list:
    """Format raw tag dicts with type classification."""
    tags = []
    for tag in raw_tags:
        start_date = tag["tag_date"]
        end_date = tag.get("end_date")

        if end_date is None:
            tag_type = "ongoing"
        elif end_date == start_date:
            tag_type = "single"
        else:
            tag_type = "range"

        tags.append({
            "id": tag["id"],
            "label": tag["label"],
            "start_date": start_date,
            "end_date": end_date,
            "type": tag_type,
        })

    return tags
