"""Topics database service for managing and searching video topics."""

import json
from pathlib import Path
from typing import List, Dict, Optional
from datetime import datetime

from ..config import get_config_dir


def get_topics_file() -> Path:
    """Get the topics database file path."""
    return get_config_dir() / "topics.json"


def load_topics_db() -> Dict:
    """Load topics database from file."""
    topics_file = get_topics_file()
    if not topics_file.exists():
        return {"topics": {}, "video_topics": {}}

    try:
        with open(topics_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    except (json.JSONDecodeError, Exception):
        return {"topics": {}, "video_topics": {}}


def save_topics_db(db: Dict) -> None:
    """Save topics database to file."""
    topics_file = get_topics_file()
    with open(topics_file, 'w', encoding='utf-8') as f:
        json.dump(db, f, indent=2, ensure_ascii=False)


def normalize_topic(topic: str) -> str:
    """Normalize topic name for consistent storage."""
    return topic.strip().lower()


def add_topics_to_video(video_id: str, topics: List[str], video_title: str = "") -> None:
    """
    Add topics to a video, creating topic entries if they don't exist.

    Args:
        video_id: The video/history item ID
        topics: List of topic strings
        video_title: Optional video title for reference
    """
    db = load_topics_db()

    for topic in topics:
        topic_key = normalize_topic(topic)
        if not topic_key:
            continue

        # Add to topics index
        if topic_key not in db["topics"]:
            db["topics"][topic_key] = {
                "name": topic.strip(),  # Keep original casing for display
                "video_ids": [],
                "created_at": datetime.now().isoformat()
            }

        # Add video to topic if not already there
        if video_id not in db["topics"][topic_key]["video_ids"]:
            db["topics"][topic_key]["video_ids"].append(video_id)

    # Add to video_topics reverse index
    if video_id not in db["video_topics"]:
        db["video_topics"][video_id] = {
            "topics": [],
            "title": video_title
        }

    # Add topics to video entry
    for topic in topics:
        topic_key = normalize_topic(topic)
        if topic_key and topic_key not in db["video_topics"][video_id]["topics"]:
            db["video_topics"][video_id]["topics"].append(topic_key)

    if video_title:
        db["video_topics"][video_id]["title"] = video_title

    save_topics_db(db)


def remove_topic_from_video(video_id: str, topic: str) -> bool:
    """
    Remove a topic from a video.

    Returns:
        True if removed, False if not found
    """
    db = load_topics_db()
    topic_key = normalize_topic(topic)

    # Remove from topics index
    if topic_key in db["topics"]:
        if video_id in db["topics"][topic_key]["video_ids"]:
            db["topics"][topic_key]["video_ids"].remove(video_id)
            # Remove topic entirely if no videos left
            if not db["topics"][topic_key]["video_ids"]:
                del db["topics"][topic_key]

    # Remove from video_topics
    if video_id in db["video_topics"]:
        if topic_key in db["video_topics"][video_id]["topics"]:
            db["video_topics"][video_id]["topics"].remove(topic_key)
            save_topics_db(db)
            return True

    save_topics_db(db)
    return False


def get_video_topics(video_id: str) -> List[str]:
    """Get all topics for a video."""
    db = load_topics_db()

    if video_id not in db["video_topics"]:
        return []

    # Return display names
    topic_keys = db["video_topics"][video_id]["topics"]
    topics = []
    for key in topic_keys:
        if key in db["topics"]:
            topics.append(db["topics"][key]["name"])
        else:
            topics.append(key)  # Fallback to key if name not found

    return topics


def get_all_topics() -> List[Dict]:
    """
    Get all topics with video counts.

    Returns:
        List of topic info dicts sorted by video count
    """
    db = load_topics_db()

    topics = []
    for key, data in db["topics"].items():
        topics.append({
            "name": data["name"],
            "key": key,
            "video_count": len(data["video_ids"]),
            "created_at": data.get("created_at")
        })

    # Sort by video count descending
    topics.sort(key=lambda x: x["video_count"], reverse=True)
    return topics


def search_topics(query: str) -> List[Dict]:
    """
    Search topics by name.

    Returns:
        List of matching topics with video counts
    """
    db = load_topics_db()
    query_lower = query.lower()

    results = []
    for key, data in db["topics"].items():
        if query_lower in key or query_lower in data["name"].lower():
            results.append({
                "name": data["name"],
                "key": key,
                "video_count": len(data["video_ids"]),
            })

    results.sort(key=lambda x: x["video_count"], reverse=True)
    return results


def get_videos_by_topic(topic: str) -> List[str]:
    """
    Get all video IDs that have a specific topic.

    Returns:
        List of video IDs
    """
    db = load_topics_db()
    topic_key = normalize_topic(topic)

    if topic_key not in db["topics"]:
        return []

    return db["topics"][topic_key]["video_ids"]


def get_related_videos(video_id: str, limit: int = 5) -> List[Dict]:
    """
    Get videos related to a given video based on shared topics.

    Returns:
        List of related video info dicts with shared topic counts
    """
    db = load_topics_db()

    if video_id not in db["video_topics"]:
        return []

    video_topic_keys = set(db["video_topics"][video_id]["topics"])

    # Count shared topics with other videos
    related = {}
    for topic_key in video_topic_keys:
        if topic_key in db["topics"]:
            for other_id in db["topics"][topic_key]["video_ids"]:
                if other_id != video_id:
                    if other_id not in related:
                        related[other_id] = {
                            "video_id": other_id,
                            "shared_topics": [],
                            "title": db["video_topics"].get(other_id, {}).get("title", "")
                        }
                    related[other_id]["shared_topics"].append(db["topics"][topic_key]["name"])

    # Sort by number of shared topics
    results = list(related.values())
    results.sort(key=lambda x: len(x["shared_topics"]), reverse=True)

    return results[:limit]


def delete_video_topics(video_id: str) -> None:
    """Remove all topics associated with a video (when video is deleted)."""
    db = load_topics_db()

    if video_id not in db["video_topics"]:
        return

    # Remove video from all topic entries
    for topic_key in db["video_topics"][video_id]["topics"]:
        if topic_key in db["topics"]:
            if video_id in db["topics"][topic_key]["video_ids"]:
                db["topics"][topic_key]["video_ids"].remove(video_id)
            # Remove topic if no videos left
            if not db["topics"][topic_key]["video_ids"]:
                del db["topics"][topic_key]

    # Remove video entry
    del db["video_topics"][video_id]

    save_topics_db(db)
