"""Pool service for aggregating entries across uploads."""

import tempfile
import zipfile
from pathlib import Path
from typing import List, Tuple

from words_to_readlang.models import Entry as LibEntry
from words_to_readlang.writers.readlang import ReadlangWriter

from ..database import db
from ..models import Entry, Upload


class PoolService:
    """Service for aggregating and managing entries across all uploads in a session."""

    @staticmethod
    def get_available_language_pairs(session_id: int) -> List[Tuple[str, str]]:
        """Get all unique language pairs in a session.

        Args:
            session_id: Session ID to check

        Returns:
            List of (source_language, target_language) tuples
        """
        pairs = (
            db.session.query(Upload.source_language, Upload.target_language)
            .filter_by(session_id=session_id)
            .distinct()
            .all()
        )
        return pairs

    @staticmethod
    def get_all_entries(
        session_id: int,
        source_language: str = None,
        target_language: str = None,
        page: int = 1,
        per_page: int = 50,
    ) -> Tuple[List[Entry], bool]:
        """Get all entries for a session across all uploads, optionally filtered by language pair.

        Args:
            session_id: Session ID to fetch entries for
            source_language: Optional source language code to filter by
            target_language: Optional target language code to filter by
            page: Page number (1-indexed)
            per_page: Number of entries per page

        Returns:
            Tuple of (entries list, has_more boolean)
        """
        query = Entry.query.join(Entry.upload).filter_by(session_id=session_id)

        # Filter by language pair if specified
        if source_language and target_language:
            query = query.filter(
                Upload.source_language == source_language,
                Upload.target_language == target_language,
            )

        query = query.order_by(Entry.id)

        # Paginate
        offset = (page - 1) * per_page
        entries = query.limit(per_page + 1).offset(offset).all()

        # Check if there are more entries
        has_more = len(entries) > per_page
        if has_more:
            entries = entries[:-1]

        return entries, has_more

    @staticmethod
    def get_stats(session_id: int, source_language: str = None, target_language: str = None) -> dict:
        """Get validation statistics for all entries in a session, optionally filtered by language pair.

        Args:
            session_id: Session ID to get stats for
            source_language: Optional source language code to filter by
            target_language: Optional target language code to filter by

        Returns:
            Dictionary with counts: {total, valid, invalid_no_example, invalid_word_missing}
        """
        query = Entry.query.join(Entry.upload).filter_by(session_id=session_id)

        # Filter by language pair if specified
        if source_language and target_language:
            query = query.filter(
                Upload.source_language == source_language,
                Upload.target_language == target_language,
            )

        total = query.count()
        valid = query.filter(Entry.validation_status == "valid").count()
        invalid_no_example = query.filter(Entry.validation_status == "invalid_no_example").count()
        invalid_word_missing = query.filter(Entry.validation_status == "invalid_word_missing").count()

        return {
            "total": total,
            "valid": valid,
            "invalid_no_example": invalid_no_example,
            "invalid_word_missing": invalid_word_missing,
        }

    @staticmethod
    def export_selected(
        session_id: int,
        entry_ids: List[int] = None,
        source_language: str = None,
        target_language: str = None,
    ) -> Tuple[Path, str, str, int, int]:
        """Export selected entries to Readlang format.

        Args:
            session_id: Session ID (for verification)
            entry_ids: List of entry IDs to export. If None or empty, exports all valid entries.
            source_language: Optional source language code to filter by
            target_language: Optional target language code to filter by

        Returns:
            Tuple of (file_path, mime_type, filename, exported_count, excluded_count)

        Raises:
            ValueError: If no valid entries to export
        """
        if entry_ids:
            # Export specific entries
            query = Entry.query.join(Entry.upload).filter(
                Entry.upload.has(session_id=session_id),
                Entry.id.in_(entry_ids)
            )

            # Filter by language pair if specified
            if source_language and target_language:
                query = query.filter(
                    Upload.source_language == source_language,
                    Upload.target_language == target_language,
                )

            entries = query.all()

            if not entries:
                raise ValueError("No entries found with the provided IDs")

            # Filter to valid entries only
            valid_entries = [e for e in entries if e.validation_status == "valid"]
            excluded_count = len(entries) - len(valid_entries)

        else:
            # Export all valid entries in session (filtered by language pair if specified)
            query = Entry.query.join(Entry.upload).filter_by(session_id=session_id)

            # Filter by language pair if specified
            if source_language and target_language:
                query = query.filter(
                    Upload.source_language == source_language,
                    Upload.target_language == target_language,
                )

            all_entries = query.all()

            if not all_entries:
                raise ValueError("No entries found for this session")

            valid_entries = [e for e in all_entries if e.validation_status == "valid"]
            excluded_count = len(all_entries) - len(valid_entries)

        if not valid_entries:
            raise ValueError("No valid entries to export. Please fix validation errors first.")

        # Convert to library Entry objects
        lib_entries = [
            LibEntry(
                word=e.current_word,
                translation=e.current_translation,
                example=e.current_example,
                score="",
                date="",
            )
            for e in valid_entries
        ]

        # Create temporary directory for output
        temp_dir = Path(tempfile.mkdtemp())
        output_path = temp_dir / "readlang.csv"

        # Use existing ReadlangWriter
        writer = ReadlangWriter()
        paths = writer.write(lib_entries, output_path, fetch_examples=False)

        # If multiple files, create ZIP
        if len(paths) > 1:
            zip_path = temp_dir / "readlang.zip"
            with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
                for path in paths:
                    zf.write(path, path.name)

            return (zip_path, "application/zip", "readlang_pool.zip", len(valid_entries), excluded_count)
        else:
            return (paths[0], "text/csv", "readlang_pool.csv", len(valid_entries), excluded_count)
