# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
AI Assistant for Video Analysis.

Provides AI-powered features:
- Video summarization
- Question answering about video content
- Finding specific moments
- Automatic chapter generation
- Key points extraction
"""

import json
import logging
import re
from typing import Any, Dict, List, Optional

logger = logging.getLogger(__name__)

from .transcribe import Transcript  # noqa: E402


class VideoAI:
    """
    AI assistant for video analysis.

    Uses the Familiar agent's LLM to provide intelligent
    analysis of video content based on transcripts.
    """

    def __init__(self, agent):
        self.agent = agent

    async def summarize_video(
        self,
        title: str,
        transcript_text: str,
        duration_seconds: int,
        max_length: int = 500,
    ) -> str:
        """
        Generate a summary of a video.

        Args:
            title: Video title
            transcript_text: Full transcript text
            duration_seconds: Video duration
            max_length: Maximum summary length in words

        Returns:
            Summary text
        """
        if not self.agent:
            return self._fallback_summarize(transcript_text)

        # Truncate transcript if too long
        transcript_text = transcript_text[:15000]

        duration_formatted = self._format_duration(duration_seconds)

        prompt = f"""Summarize this video transcript in {max_length} words or less.
Include the key points, main arguments, and any important conclusions.

Video Title: {title}
Duration: {duration_formatted}

Transcript:
{transcript_text}

Summary:"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=max_length * 2,
                temperature=0.3,
            )
            return response.strip()
        except Exception as e:
            logger.error(f"AI summarization error: {e}")
            return self._fallback_summarize(transcript_text)

    def _fallback_summarize(self, text: str) -> str:
        """Simple extractive summary as fallback."""
        sentences = re.split(r"[.!?]+", text)
        sentences = [s.strip() for s in sentences if len(s.strip()) > 20]

        # Take first few sentences
        summary = ". ".join(sentences[:5])
        if summary and not summary.endswith("."):
            summary += "."

        return summary[:500] if summary else "Unable to generate summary."

    async def answer_question(
        self,
        question: str,
        title: str,
        transcript: Transcript,
    ) -> str:
        """
        Answer a question about a video.

        Args:
            question: User's question
            title: Video title
            transcript: Video transcript

        Returns:
            Answer with timestamp references
        """
        if not self.agent:
            return "AI assistant not available."

        # Get relevant segments
        relevant = transcript.search(question, max_results=5)

        # Build context from transcript
        context_parts = []
        for seg in relevant:
            context_parts.append(f"[{seg['timestamp_formatted']}] {seg['text']}")

        # Also include surrounding text if search didn't find much
        if len(relevant) < 3:
            # Add first part of transcript for context
            early_text = " ".join(
                f"[{s.start_formatted}] {s.text}" for s in transcript.segments[:10]
            )
            context_parts.insert(0, early_text)

        context = "\n".join(context_parts)

        prompt = f"""Based on this video transcript, answer the question.
Include timestamps when referencing specific parts.

Video Title: {title}

Relevant Transcript Sections:
{context}

Question: {question}

Answer (include timestamps like [MM:SS] when referencing specific parts):"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=500,
                temperature=0.3,
            )
            return response.strip()
        except Exception as e:
            logger.error(f"AI question answering error: {e}")
            return f"Error answering question: {str(e)}"

    async def find_moment(
        self,
        description: str,
        transcript: Transcript,
    ) -> Optional[Dict[str, Any]]:
        """
        Find a specific moment in a video based on description.

        Args:
            description: Description of what to find
            transcript: Video transcript

        Returns:
            Moment info with timestamp
        """
        if not self.agent:
            # Fallback: simple search
            results = transcript.search(description)
            if results:
                return {
                    "timestamp": results[0]["timestamp"],
                    "timestamp_formatted": results[0]["timestamp_formatted"],
                    "text": results[0]["text"],
                    "confidence": 0.5,
                }
            return None

        # Build transcript with timestamps
        transcript_text = "\n".join(f"[{s.start_formatted}] {s.text}" for s in transcript.segments)

        # Truncate if too long
        transcript_text = transcript_text[:10000]

        prompt = f"""Find the timestamp where this happens in the video.
Return ONLY a JSON object with the timestamp.

Looking for: {description}

Transcript:
{transcript_text}

Return JSON with format:
{{"timestamp_formatted": "MM:SS", "timestamp_seconds": 123.45, "text": "relevant quote", "confidence": 0.9}}

JSON:"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=200,
                temperature=0.1,
            )

            # Parse JSON from response
            json_match = re.search(r"\{[^}]+\}", response)
            if json_match:
                data = json.loads(json_match.group())
                return {
                    "timestamp": data.get("timestamp_seconds", 0),
                    "timestamp_formatted": data.get("timestamp_formatted", "0:00"),
                    "text": data.get("text", ""),
                    "confidence": data.get("confidence", 0.5),
                }
        except Exception as e:
            logger.error(f"AI find moment error: {e}")

        # Fallback to text search
        results = transcript.search(description)
        if results:
            return {
                "timestamp": results[0]["timestamp"],
                "timestamp_formatted": results[0]["timestamp_formatted"],
                "text": results[0]["text"],
                "confidence": 0.5,
            }

        return None

    async def generate_chapters(
        self,
        transcript: Transcript,
        max_chapters: int = 10,
    ) -> List[Dict[str, Any]]:
        """
        Generate chapters from video transcript.

        Args:
            transcript: Video transcript
            max_chapters: Maximum number of chapters

        Returns:
            List of chapters with timestamps and titles
        """
        if not self.agent:
            return self._fallback_chapters(transcript, max_chapters)

        # Build transcript with timestamps
        transcript_text = "\n".join(f"[{s.start_formatted}] {s.text}" for s in transcript.segments)

        # Truncate if too long
        transcript_text = transcript_text[:12000]

        prompt = f"""Analyze this video transcript and generate {max_chapters} or fewer chapter markers.
Each chapter should mark a significant topic change or new section.

Transcript:
{transcript_text}

Return ONLY a JSON array of chapters with format:
[{{"start": "MM:SS", "start_seconds": 123, "title": "Chapter Title"}}]

JSON array:"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=1000,
                temperature=0.3,
            )

            # Parse JSON array from response
            json_match = re.search(r"\[[\s\S]*\]", response)
            if json_match:
                chapters = json.loads(json_match.group())
                return [
                    {
                        "start": ch.get("start_seconds", 0),
                        "title": ch.get("title", f"Chapter {i + 1}"),
                    }
                    for i, ch in enumerate(chapters)
                ]
        except Exception as e:
            logger.error(f"AI chapter generation error: {e}")

        return self._fallback_chapters(transcript, max_chapters)

    def _fallback_chapters(
        self,
        transcript: Transcript,
        max_chapters: int,
    ) -> List[Dict[str, Any]]:
        """Generate simple time-based chapters."""
        if not transcript.segments:
            return []

        duration = transcript.duration
        chapter_length = duration / min(max_chapters, 5)

        chapters = []
        current_time = 0

        while current_time < duration:
            # Find segment at this time
            seg = transcript.get_text_at(current_time)

            # Get first few words as title
            if seg:
                words = seg.text.split()[:5]
                title = " ".join(words) + "..." if len(words) >= 5 else seg.text
            else:
                title = f"Part {len(chapters) + 1}"

            chapters.append(
                {
                    "start": current_time,
                    "title": title,
                }
            )

            current_time += chapter_length

        return chapters

    async def extract_key_points(
        self,
        transcript: Transcript,
        max_points: int = 10,
    ) -> List[Dict[str, Any]]:
        """
        Extract key points from a video.

        Args:
            transcript: Video transcript
            max_points: Maximum number of points

        Returns:
            List of key points with timestamps
        """
        if not self.agent:
            return []

        transcript_text = transcript.full_text[:10000]

        prompt = f"""Extract the {max_points} most important key points from this video transcript.
Each point should be a concise statement of a main idea or conclusion.

Transcript:
{transcript_text}

Return ONLY a JSON array with format:
[{{"point": "Key point text", "importance": 1-10}}]

JSON array:"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=1000,
                temperature=0.3,
            )

            json_match = re.search(r"\[[\s\S]*\]", response)
            if json_match:
                points = json.loads(json_match.group())

                # Try to find timestamps for each point
                for point in points:
                    results = transcript.search(point.get("point", ""), max_results=1)
                    if results:
                        point["timestamp"] = results[0]["timestamp"]
                        point["timestamp_formatted"] = results[0]["timestamp_formatted"]

                return points
        except Exception as e:
            logger.error(f"AI key points extraction error: {e}")

        return []

    async def compare_videos(
        self,
        transcripts: List[Dict[str, Any]],
    ) -> str:
        """
        Compare multiple videos.

        Args:
            transcripts: List of {'title': str, 'text': str}

        Returns:
            Comparison text
        """
        if not self.agent or len(transcripts) < 2:
            return "Need at least 2 videos and AI to compare."

        # Build comparison prompt
        video_texts = []
        for i, t in enumerate(transcripts[:5]):  # Limit to 5
            video_texts.append(f"Video {i + 1}: {t['title']}\n{t['text'][:3000]}")

        prompt = f"""Compare these videos and highlight:
1. Common themes or topics
2. Key differences in perspective or approach
3. Which video covers what best

{chr(10).join(video_texts)}

Comparison:"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=800,
                temperature=0.4,
            )
            return response.strip()
        except Exception as e:
            logger.error(f"AI comparison error: {e}")
            return f"Error comparing videos: {str(e)}"

    async def generate_study_notes(
        self,
        transcript: Transcript,
    ) -> str:
        """
        Generate study notes from a video.

        Useful for educational content.
        """
        if not self.agent:
            return "AI not available."

        transcript_text = transcript.full_text[:12000]

        prompt = f"""Create comprehensive study notes from this video transcript.
Include:
- Main concepts and definitions
- Key facts and figures
- Important examples
- Questions for review

Transcript:
{transcript_text}

Study Notes:"""

        try:
            response = await self.agent.llm.generate(
                prompt,
                max_tokens=1500,
                temperature=0.3,
            )
            return response.strip()
        except Exception as e:
            logger.error(f"AI study notes error: {e}")
            return f"Error generating study notes: {str(e)}"

    def _format_duration(self, seconds: int) -> str:
        """Format duration as human-readable."""
        hours, remainder = divmod(seconds, 3600)
        minutes, secs = divmod(remainder, 60)

        parts = []
        if hours:
            parts.append(f"{hours} hour{'s' if hours > 1 else ''}")
        if minutes:
            parts.append(f"{minutes} minute{'s' if minutes > 1 else ''}")
        if secs and not hours:
            parts.append(f"{secs} second{'s' if secs > 1 else ''}")

        return ", ".join(parts) if parts else "0 seconds"
