"""
Service for managing research sources/resources in the database.

This service handles saving and retrieving sources from research
in a proper relational way using the ResearchResource table.
"""

from typing import List, Dict, Any, Optional
from datetime import datetime, UTC
from loguru import logger

from ...database.models import ResearchResource, ResearchHistory
from ...database.session_context import get_user_db_session


class ResearchSourcesService:
    """Service for managing research sources in the database."""

    @staticmethod
    def save_research_sources(
        research_id: str,
        sources: List[Dict[str, Any]],
        username: Optional[str] = None,
    ) -> int:
        """
        Save sources from research to the ResearchResource table.

        Args:
            research_id: The UUID of the research
            sources: List of source dictionaries with url, title, snippet, etc.
            username: Username for database access

        Returns:
            Number of sources saved
        """
        if not sources:
            logger.info(f"No sources to save for research {research_id}")
            return 0

        saved_count = 0

        try:
            with get_user_db_session(username) as db_session:
                # First check if resources already exist for this research
                existing = (
                    db_session.query(ResearchResource)
                    .filter_by(research_id=research_id)
                    .count()
                )

                if existing > 0:
                    logger.info(
                        f"Research {research_id} already has {existing} resources, skipping save"
                    )
                    return existing

                # Save each source as a ResearchResource
                for source in sources:
                    try:
                        # Extract fields from various possible formats
                        url = source.get("url", "") or source.get("link", "")
                        title = source.get("title", "") or source.get(
                            "name", ""
                        )
                        snippet = (
                            source.get("snippet", "")
                            or source.get("content_preview", "")
                            or source.get("description", "")
                        )
                        source_type = source.get("source_type", "web")

                        # Skip if no URL
                        if not url:
                            continue

                        # Create resource record
                        resource = ResearchResource(
                            research_id=research_id,
                            title=title or "Untitled",
                            url=url,
                            content_preview=snippet[:1000]
                            if snippet
                            else None,  # Limit preview length
                            source_type=source_type,
                            resource_metadata={
                                "added_at": datetime.now(UTC).isoformat(),
                                "original_data": source,  # Keep original data for reference
                            },
                            created_at=datetime.now(UTC).isoformat(),
                        )

                        db_session.add(resource)
                        saved_count += 1

                    except Exception as e:
                        logger.warning(
                            f"Failed to save source {source.get('url', 'unknown')}: {e}"
                        )
                        continue

                # Commit all resources
                if saved_count > 0:
                    db_session.commit()
                    logger.info(
                        f"Saved {saved_count} sources for research {research_id}"
                    )

        except Exception:
            logger.exception("Error saving research sources")
            raise

        return saved_count

    @staticmethod
    def get_research_sources(
        research_id: str, username: Optional[str] = None
    ) -> List[Dict[str, Any]]:
        """
        Get all sources for a research from the database.

        Args:
            research_id: The UUID of the research
            username: Username for database access

        Returns:
            List of source dictionaries
        """
        sources = []

        try:
            with get_user_db_session(username) as db_session:
                resources = (
                    db_session.query(ResearchResource)
                    .filter_by(research_id=research_id)
                    .order_by(ResearchResource.id.asc())
                    .all()
                )

                for resource in resources:
                    sources.append(
                        {
                            "id": resource.id,
                            "url": resource.url,
                            "title": resource.title,
                            "snippet": resource.content_preview,
                            "content_preview": resource.content_preview,
                            "source_type": resource.source_type,
                            "metadata": resource.resource_metadata or {},
                            "created_at": resource.created_at,
                        }
                    )

                logger.info(
                    f"Retrieved {len(sources)} sources for research {research_id}"
                )

        except Exception:
            logger.exception("Error retrieving research sources")
            raise

        return sources

    @staticmethod
    def copy_sources_to_new_research(
        from_research_id: str,
        to_research_id: str,
        source_ids: Optional[List[int]] = None,
        username: Optional[str] = None,
    ) -> int:
        """
        Copy sources from one research to another (useful for follow-ups).

        Args:
            from_research_id: Source research ID
            to_research_id: Destination research ID
            source_ids: Optional list of specific source IDs to copy
            username: Username for database access

        Returns:
            Number of sources copied
        """
        copied_count = 0

        try:
            with get_user_db_session(username) as db_session:
                # Get sources to copy
                query = db_session.query(ResearchResource).filter_by(
                    research_id=from_research_id
                )

                if source_ids:
                    query = query.filter(ResearchResource.id.in_(source_ids))

                sources_to_copy = query.all()

                # Copy each source
                for source in sources_to_copy:
                    new_resource = ResearchResource(
                        research_id=to_research_id,
                        title=source.title,
                        url=source.url,
                        content_preview=source.content_preview,
                        source_type=source.source_type,
                        resource_metadata={
                            **(source.resource_metadata or {}),
                            "copied_from": from_research_id,
                            "copied_at": datetime.now(UTC).isoformat(),
                        },
                        created_at=datetime.now(UTC).isoformat(),
                    )

                    db_session.add(new_resource)
                    copied_count += 1

                if copied_count > 0:
                    db_session.commit()
                    logger.info(
                        f"Copied {copied_count} sources from {from_research_id} to {to_research_id}"
                    )

        except Exception:
            logger.exception("Error copying research sources")
            raise

        return copied_count

    @staticmethod
    def update_research_with_sources(
        research_id: str,
        all_links_of_system: List[Dict[str, Any]],
        username: Optional[str] = None,
    ) -> bool:
        """
        Update a completed research with its sources.
        This should be called when research completes.

        Args:
            research_id: The UUID of the research
            all_links_of_system: List of all sources found during research
            username: Username for database access

        Returns:
            True if successful
        """
        try:
            # Save sources to ResearchResource table
            saved_count = ResearchSourcesService.save_research_sources(
                research_id, all_links_of_system, username
            )

            # Also update the research metadata to include source count
            with get_user_db_session(username) as db_session:
                research = (
                    db_session.query(ResearchHistory)
                    .filter_by(id=research_id)
                    .first()
                )

                if research:
                    if not research.research_meta:
                        research.research_meta = {}

                    # Update metadata with source information
                    research.research_meta["sources_count"] = saved_count
                    research.research_meta["has_sources"] = saved_count > 0

                    db_session.commit()
                    logger.info(
                        f"Updated research {research_id} with {saved_count} sources"
                    )
                    return True
                else:
                    logger.warning(
                        f"Research {research_id} not found for source update"
                    )
                    return False

        except Exception:
            logger.exception("Error updating research with sources")
            return False
