"""
Ripgrep-powered search for Video Viewer Bot.
Fast direct search using rg command.
"""

import json
import os
import re
import subprocess
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

from data_reader import _parse_product_dir

NFS_BASE = os.getenv("NFS_BASE", "/mnt/video")


@dataclass
class SearchResult:
    task_id: str
    product_id: str
    product_name: Optional[str]
    reason: str  # Why this matched
    has_video: bool
    source: str = "wb"  # marketplace prefix


def search_videos(query: str, context: str = "") -> list[SearchResult]:
    """
    Search videos using ripgrep.
    Detects query type and searches appropriate files.
    """
    query_lower = query.lower().strip()
    results = []

    # Detect search type based on keywords
    if _is_rating_search(query_lower):
        rating = "good" if any(w in query_lower for w in ["хорош", "good", "удачн", "лучш"]) else "bad"
        results = _search_by_rating(rating)
    elif _is_error_search(query_lower):
        results = _search_by_errors()
    elif _is_category_search(query_lower):
        category = _extract_category(query_lower)
        results = _search_by_category(category)
    else:
        # General text search across metadata
        results = _search_by_text(query)

    return results[:5]  # Max 5 results


def _is_rating_search(query: str) -> bool:
    """Check if query is about ratings."""
    rating_words = ["хорош", "плох", "good", "bad", "рейтинг", "оценк", "удачн", "неудачн", "лучш", "худш"]
    return any(w in query for w in rating_words)


def _is_error_search(query: str) -> bool:
    """Check if query is about errors."""
    error_words = ["ошибк", "error", "артефакт", "artifact", "сбой", "fail", "проблем"]
    return any(w in query for w in error_words)


def _is_category_search(query: str) -> bool:
    """Check if query mentions specific category."""
    categories = ["косметик", "cosmetic", "одежд", "cloth", "электроник", "electronic",
                  "еда", "food", "посуд", "kitchen", "игрушк", "toy"]
    return any(c in query for c in categories)


def _extract_category(query: str) -> str:
    """Extract category keyword from query."""
    # Return the query itself for broad matching
    return query


def _search_by_rating(rating: str) -> list[SearchResult]:
    """Search for videos with specific rating in activity.log files."""
    results = []

    # Search all activity.log files for RATE entries
    try:
        rg_result = subprocess.run(
            ["rg", "-l", f"RATE.*{rating}", NFS_BASE, "-g", "activity.log"],
            capture_output=True, text=True, timeout=30
        )

        activity_files = rg_result.stdout.strip().split("\n")

        for activity_file in activity_files:
            if not activity_file:
                continue

            # Parse activity.log to get task_ids with this rating
            product_dir = Path(activity_file).parent
            parsed = _parse_product_dir(product_dir.name)
            if not parsed:
                continue
            source, product_id = parsed

            with open(activity_file) as f:
                for line in f:
                    if f" | RATE | " in line and f" | {rating}" in line.lower():
                        parts = line.split(" | ")
                        if len(parts) >= 5:
                            task_id = parts[3].strip()

                            # Check if video exists
                            video_path = product_dir / task_id / "videos" / "video.mp4"
                            if video_path.exists():
                                # Get product name from metadata
                                product_name = _get_product_name(product_dir / task_id)
                                results.append(SearchResult(
                                    task_id=task_id,
                                    product_id=product_id,
                                    product_name=product_name,
                                    reason=f"Оценка: {rating}",
                                    has_video=True,
                                    source=source,
                                ))
    except (subprocess.TimeoutExpired, Exception):
        pass

    return results


def _search_by_errors() -> list[SearchResult]:
    """Search for generations with errors."""
    results = []

    try:
        # Search metadata.json for non-empty errors
        rg_result = subprocess.run(
            ["rg", "-l", '"errors":\\s*\\[\\s*"', NFS_BASE, "-g", "metadata.json"],
            capture_output=True, text=True, timeout=30
        )

        metadata_files = rg_result.stdout.strip().split("\n")

        for meta_file in metadata_files:
            if not meta_file:
                continue

            meta_path = Path(meta_file)
            gen_dir = meta_path.parent
            task_id = gen_dir.name
            product_dir = gen_dir.parent
            parsed = _parse_product_dir(product_dir.name)
            if not parsed:
                continue
            source, product_id = parsed

            # Read metadata for details
            try:
                with open(meta_file) as f:
                    meta = json.load(f)
                    errors = meta.get("errors", [])
                    if errors:
                        error_preview = errors[0][:50] if errors else ""
                        video_path = gen_dir / "videos" / "video.mp4"
                        results.append(SearchResult(
                            task_id=task_id,
                            product_id=product_id,
                            product_name=meta.get("product_name"),
                            reason=f"Ошибка: {error_preview}...",
                            has_video=video_path.exists(),
                            source=source,
                        ))
            except (json.JSONDecodeError, Exception):
                pass

    except (subprocess.TimeoutExpired, Exception):
        pass

    return results


def _search_by_category(category: str) -> list[SearchResult]:
    """Search by category/archetype in generation.log."""
    results = []

    try:
        # Search generation.log for category mentions
        rg_result = subprocess.run(
            ["rg", "-i", "-l", category, NFS_BASE, "-g", "generation.log"],
            capture_output=True, text=True, timeout=30
        )

        log_files = rg_result.stdout.strip().split("\n")

        for log_file in log_files:
            if not log_file:
                continue

            log_path = Path(log_file)
            gen_dir = log_path.parent
            task_id = gen_dir.name
            product_dir = gen_dir.parent
            parsed = _parse_product_dir(product_dir.name)
            if not parsed:
                continue
            source, product_id = parsed

            # Read generation.log for context
            try:
                with open(log_file) as f:
                    log_data = json.load(f)
                    stages = log_data.get("stages", {})
                    stage2 = stages.get("stage2", {})
                    story_vision = stage2.get("story_vision", {})

                    archetype = story_vision.get("archetype", "")
                    cat = story_vision.get("category", "")

                    video_path = gen_dir / "videos" / "video.mp4"

                    # Get product name from metadata
                    product_name = _get_product_name(gen_dir)

                    results.append(SearchResult(
                        task_id=task_id,
                        product_id=product_id,
                        product_name=product_name,
                        reason=f"{cat} / {archetype}" if cat or archetype else "Совпадение по запросу",
                        has_video=video_path.exists(),
                        source=source,
                    ))
            except (json.JSONDecodeError, Exception):
                pass

    except (subprocess.TimeoutExpired, Exception):
        pass

    return results


def _search_by_text(query: str) -> list[SearchResult]:
    """General text search across metadata files."""
    results = []

    try:
        # Search in metadata.json for product names and other text
        rg_result = subprocess.run(
            ["rg", "-i", "-l", query, NFS_BASE, "-g", "metadata.json"],
            capture_output=True, text=True, timeout=30
        )

        metadata_files = rg_result.stdout.strip().split("\n")

        for meta_file in metadata_files:
            if not meta_file:
                continue

            meta_path = Path(meta_file)
            gen_dir = meta_path.parent
            task_id = gen_dir.name
            product_dir = gen_dir.parent
            parsed = _parse_product_dir(product_dir.name)
            if not parsed:
                continue
            source, product_id = parsed

            try:
                with open(meta_file) as f:
                    meta = json.load(f)
                    video_path = gen_dir / "videos" / "video.mp4"
                    results.append(SearchResult(
                        task_id=task_id,
                        product_id=product_id,
                        product_name=meta.get("product_name"),
                        reason="Совпадение в метаданных",
                        has_video=video_path.exists(),
                        source=source,
                    ))
            except (json.JSONDecodeError, Exception):
                pass

        # Also search in generation.log
        if len(results) < 5:
            rg_result = subprocess.run(
                ["rg", "-i", "-l", query, NFS_BASE, "-g", "generation.log"],
                capture_output=True, text=True, timeout=30
            )

            log_files = rg_result.stdout.strip().split("\n")
            seen_tasks = {r.task_id for r in results}

            for log_file in log_files:
                if not log_file or len(results) >= 5:
                    break

                log_path = Path(log_file)
                gen_dir = log_path.parent
                task_id = gen_dir.name

                if task_id in seen_tasks:
                    continue

                product_dir = gen_dir.parent
                parsed = _parse_product_dir(product_dir.name)
                if not parsed:
                    continue
                source, product_id = parsed

                video_path = gen_dir / "videos" / "video.mp4"
                product_name = _get_product_name(gen_dir)

                results.append(SearchResult(
                    task_id=task_id,
                    product_id=product_id,
                    product_name=product_name,
                    reason="Совпадение в логе генерации",
                    has_video=video_path.exists(),
                    source=source,
                ))

    except (subprocess.TimeoutExpired, Exception):
        pass

    return results


def _get_product_name(gen_dir: Path) -> Optional[str]:
    """Get product name from metadata.json in generation directory."""
    meta_file = gen_dir / "metadata.json"
    if meta_file.exists():
        try:
            with open(meta_file) as f:
                meta = json.load(f)
                return meta.get("product_name")
        except (json.JSONDecodeError, Exception):
            pass
    return None


def format_search_results(results: list[SearchResult]) -> str:
    """Format search results for Telegram display, grouped by product."""
    if not results:
        return "Ничего не найдено по вашему запросу."

    # Group results by (source, product_id)
    by_product = {}
    for r in results:
        key = (r.source, r.product_id)
        if key not in by_product:
            by_product[key] = {
                "product_name": r.product_name,
                "videos": []
            }
        by_product[key]["videos"].append(r)

    lines = [f"Найдено {len(results)} видео в {len(by_product)} товарах:\n"]

    for (source, product_id), data in by_product.items():
        name = data["product_name"]
        if name and len(name) > 40:
            name = name[:40] + "..."
        name = name or "—"

        # Product header with clickable link
        lines.append(f"📦 /p_{source}_{product_id}")
        lines.append(f"   {name}")

        # Videos under this product
        for v in data["videos"]:
            emoji = "🎬" if v.has_video else "❌"
            lines.append(f"   {emoji} /v_{v.task_id}")
            if v.reason:
                lines.append(f"      {v.reason}")

        lines.append("")

    return "\n".join(lines)
