"""Project and Dashboard API routes for Knowledge Repository v3."""

from fastapi import APIRouter, HTTPException
from typing import List, Optional

from ..models import (
    ProjectDataModel,
    ProjectSummaryModel,
    ProjectListResponse,
    DashboardStatsModel,
    ActivityModel,
    ActivityFeedResponse,
    PersonalNoteModel,
    AddNoteRequest,
    UpdateNoteRequest,
    UpdateTagsRequest,
    KnowledgeGraphModel,
    TopicModel,
    TopicsResponse,
    JournalEntryModel,
    JournalResponse,
    ExtractRequest,
)
from ..services.project import (
    get_project,
    save_project,
    delete_project,
    load_projects,
    add_note_to_project,
    update_note,
    delete_note,
    toggle_star,
    update_tags,
    get_dashboard_stats,
    get_recent_activity,
    ProjectData,
)
from ..services.knowledge_graph import (
    load_graph,
    build_graph_from_projects,
    get_graph_stats,
    get_topic_clusters,
    find_related_videos,
    search_graph,
)
from ..services.history import (
    migrate_history_to_projects,
    get_or_create_project,
)
from collections import defaultdict

router = APIRouter()


# =============================================================================
# Dashboard Endpoints
# =============================================================================

@router.get("/api/dashboard/stats", response_model=DashboardStatsModel)
async def get_stats():
    """Get dashboard statistics."""
    stats = get_dashboard_stats()
    return DashboardStatsModel(**stats)


@router.get("/api/dashboard/activity", response_model=ActivityFeedResponse)
async def get_activity(limit: int = 20):
    """Get recent activity feed."""
    activities = get_recent_activity(limit)
    return ActivityFeedResponse(
        activities=[ActivityModel(**a) for a in activities]
    )


@router.post("/api/dashboard/migrate")
async def migrate_history():
    """Migrate v2 history items to v3 project format."""
    result = migrate_history_to_projects()
    return result


# =============================================================================
# Project List Endpoints
# =============================================================================

@router.get("/api/projects", response_model=ProjectListResponse)
async def list_projects(
    search: Optional[str] = None,
    starred: Optional[bool] = None,
    tag: Optional[str] = None,
    limit: int = 50,
    offset: int = 0
):
    """List all projects with optional filtering."""
    projects = load_projects()

    # Apply filters
    if search:
        search_lower = search.lower()
        projects = [
            p for p in projects
            if search_lower in p.get('title', '').lower()
            or search_lower in p.get('channel', '').lower()
            or any(search_lower in t.lower() for t in p.get('tags', []))
        ]

    if starred is not None:
        projects = [p for p in projects if p.get('is_starred') == starred]

    if tag:
        projects = [p for p in projects if tag in p.get('tags', [])]

    total = len(projects)
    projects = projects[offset:offset + limit]

    # Convert to summary models
    summaries = []
    for p in projects:
        project_data = ProjectData.from_dict(p)
        summaries.append(ProjectSummaryModel(
            video_id=project_data.video_id,
            title=project_data.title,
            url=project_data.url,
            channel=project_data.channel,
            duration=project_data.duration,
            thumbnail=project_data.thumbnail,
            is_starred=project_data.is_starred,
            tags=project_data.tags,
            created_at=project_data.created_at,
            extraction_status=project_data.extraction_status,
            insight_count=len(project_data.insights),
            entity_count=project_data.entities.count(),
            note_count=len(project_data.notes)
        ))

    return ProjectListResponse(projects=summaries, total=total)


# =============================================================================
# Single Project Endpoints
# =============================================================================

@router.get("/api/project/{video_id}")
async def get_project_data(video_id: str):
    """Get complete project data."""
    # First try to get from projects, then fallback to history
    project = get_project(video_id)

    if not project:
        # Try to create from history
        project_dict = get_or_create_project(video_id)
        if not project_dict:
            raise HTTPException(status_code=404, detail="Project not found")
        return project_dict

    return project.to_dict()


@router.delete("/api/project/{video_id}")
async def delete_project_endpoint(video_id: str):
    """Delete a project."""
    success = delete_project(video_id)
    if not success:
        raise HTTPException(status_code=404, detail="Project not found")
    return {"success": True}


@router.post("/api/project/{video_id}/star")
async def toggle_star_endpoint(video_id: str):
    """Toggle star status for a project."""
    new_status = toggle_star(video_id)
    if new_status is None:
        raise HTTPException(status_code=404, detail="Project not found")
    return {"is_starred": new_status}


@router.put("/api/project/{video_id}/tags")
async def update_tags_endpoint(video_id: str, request: UpdateTagsRequest):
    """Update tags for a project."""
    result = update_tags(video_id, request.tags)
    if result is None:
        raise HTTPException(status_code=404, detail="Project not found")
    return {"tags": result}


# =============================================================================
# Personal Notes Endpoints
# =============================================================================

@router.get("/api/project/{video_id}/notes")
async def get_notes(video_id: str):
    """Get all notes for a project."""
    project = get_project(video_id)
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    return {
        "notes": [n.to_dict() for n in project.notes]
    }


@router.post("/api/project/{video_id}/notes")
async def add_note(video_id: str, request: AddNoteRequest):
    """Add a note to a project."""
    note = add_note_to_project(
        video_id,
        request.content,
        request.timestamp,
        request.tags
    )
    if not note:
        raise HTTPException(status_code=404, detail="Project not found")

    return note.to_dict()


@router.put("/api/project/{video_id}/notes/{note_id}")
async def update_note_endpoint(video_id: str, note_id: str, request: UpdateNoteRequest):
    """Update a note."""
    note = update_note(video_id, note_id, request.content, request.tags)
    if not note:
        raise HTTPException(status_code=404, detail="Note not found")

    return note.to_dict()


@router.delete("/api/project/{video_id}/notes/{note_id}")
async def delete_note_endpoint(video_id: str, note_id: str):
    """Delete a note."""
    success = delete_note(video_id, note_id)
    if not success:
        raise HTTPException(status_code=404, detail="Note not found")

    return {"success": True}


# =============================================================================
# Connections Endpoints
# =============================================================================

@router.get("/api/project/{video_id}/connections")
async def get_connections(video_id: str, limit: int = 10):
    """Get related videos for a project."""
    connections = find_related_videos(video_id, limit)
    return {"connections": connections}


# =============================================================================
# Knowledge Graph Endpoints
# =============================================================================

@router.get("/api/graph")
async def get_knowledge_graph():
    """Get the complete knowledge graph."""
    graph = load_graph()
    return graph.to_dict()


@router.post("/api/graph/rebuild")
async def rebuild_graph():
    """Rebuild the knowledge graph from all projects."""
    graph = build_graph_from_projects()
    stats = get_graph_stats()
    return {
        "success": True,
        "stats": stats
    }


@router.get("/api/graph/stats")
async def get_graph_statistics():
    """Get knowledge graph statistics."""
    return get_graph_stats()


@router.get("/api/graph/search")
async def search_knowledge_graph(query: str, limit: int = 20):
    """Search the knowledge graph."""
    results = search_graph(query)[:limit]
    return {"results": results}


# =============================================================================
# Topics Endpoints
# =============================================================================

@router.get("/api/topics", response_model=TopicsResponse)
async def get_topics():
    """Get all topics with their video counts."""
    clusters = get_topic_clusters()

    topics = [
        TopicModel(
            name=c['topic'],
            video_count=c['video_count'],
            videos=[v['video_id'] for v in c['videos']]
        )
        for c in clusters
    ]

    return TopicsResponse(topics=topics, total=len(topics))


@router.get("/api/topics/{topic}")
async def get_topic_detail(topic: str):
    """Get details for a specific topic."""
    clusters = get_topic_clusters()

    for c in clusters:
        if c['topic'].lower() == topic.lower():
            return c

    raise HTTPException(status_code=404, detail="Topic not found")


# =============================================================================
# Learning Journal Endpoints
# =============================================================================

@router.get("/api/journal", response_model=JournalResponse)
async def get_journal(limit: int = 30):
    """Get learning journal entries grouped by date."""
    activities = get_recent_activity(limit * 5)  # Get more to group by date

    # Group by date
    by_date = defaultdict(list)
    for activity in activities:
        timestamp = activity.get('timestamp', '')
        if timestamp:
            date = timestamp.split('T')[0]  # Extract date part
            by_date[date].append(ActivityModel(**activity))

    # Convert to journal entries
    entries = [
        JournalEntryModel(date=date, entries=activities)
        for date, activities in sorted(by_date.items(), reverse=True)
    ][:limit]

    return JournalResponse(entries=entries)


# =============================================================================
# Extraction Pipeline Endpoints
# =============================================================================

@router.post("/api/project/{video_id}/extract")
async def run_extraction(video_id: str, request: ExtractRequest = None):
    """
    Run the extraction pipeline on a project.

    Extracts entities, insights, quotes, facts, and semantic sections.
    """
    from ..services.extraction import run_extraction_and_save

    # Get request parameters or use defaults
    if request is None:
        request = ExtractRequest()

    try:
        result = await run_extraction_and_save(
            video_id=video_id,
            extract_entities_flag=request.extract_entities,
            extract_insights_flag=request.extract_insights,
            extract_quotes_flag=request.extract_quotes,
            extract_facts_flag=request.extract_facts,
            extract_sections_flag=request.extract_sections
        )

        if "error" in result and result["error"] == "Project not found":
            raise HTTPException(status_code=404, detail="Project not found")

        return result

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/api/project/{video_id}/extract/entities")
async def extract_entities_only(video_id: str):
    """Extract only entities from a project."""
    from ..services.extraction import run_extraction_and_save

    result = await run_extraction_and_save(
        video_id=video_id,
        extract_entities_flag=True,
        extract_insights_flag=False,
        extract_quotes_flag=False,
        extract_facts_flag=False,
        extract_sections_flag=False
    )

    if "error" in result and result["error"] == "Project not found":
        raise HTTPException(status_code=404, detail="Project not found")

    return result


@router.post("/api/project/{video_id}/extract/insights")
async def extract_insights_only(video_id: str):
    """Extract only insights from a project."""
    from ..services.extraction import run_extraction_and_save

    result = await run_extraction_and_save(
        video_id=video_id,
        extract_entities_flag=False,
        extract_insights_flag=True,
        extract_quotes_flag=False,
        extract_facts_flag=False,
        extract_sections_flag=False
    )

    if "error" in result and result["error"] == "Project not found":
        raise HTTPException(status_code=404, detail="Project not found")

    return result


@router.get("/api/project/{video_id}/entities")
async def get_entities(video_id: str):
    """Get extracted entities for a project."""
    project = get_project(video_id)
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    return {
        "entities": project.entities.to_dict(),
        "total": project.entities.count()
    }


@router.get("/api/project/{video_id}/insights")
async def get_insights(video_id: str):
    """Get extracted insights for a project."""
    project = get_project(video_id)
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    return {
        "insights": [i.to_dict() for i in project.insights],
        "total": len(project.insights)
    }


@router.get("/api/project/{video_id}/quotes")
async def get_quotes(video_id: str):
    """Get extracted quotes for a project."""
    project = get_project(video_id)
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    return {
        "quotes": [q.to_dict() for q in project.quotes],
        "total": len(project.quotes)
    }


@router.get("/api/project/{video_id}/facts")
async def get_facts(video_id: str):
    """Get extracted facts for a project."""
    project = get_project(video_id)
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    return {
        "facts": [f.to_dict() for f in project.facts],
        "total": len(project.facts)
    }


@router.get("/api/project/{video_id}/sections")
async def get_sections(video_id: str):
    """Get semantic sections for a project."""
    project = get_project(video_id)
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    return {
        "sections": [s.to_dict() for s in project.sections],
        "total": len(project.sections)
    }
