"""Auto-suggest projects from unscoped atom patterns."""

from __future__ import annotations

from collections import Counter

# Avoid circular import — store is passed in at runtime
from typing import TYPE_CHECKING

from pydantic import BaseModel

from sulci_core.models import KnowledgeAtom

if TYPE_CHECKING:
    from sulci_core.store import KnowledgeStore


class ProjectSuggestion(BaseModel):
    """A proposed project based on atom clustering."""

    name: str
    description: str
    atom_ids: list[str]
    confidence: float
    reason: str


SUBJECT_THRESHOLD = 3  # Minimum atoms with same subject to trigger suggestion


class ProjectSuggestionEngine:
    """Analyze unscoped atoms and suggest project groupings."""

    async def suggest_projects(self, store: KnowledgeStore) -> list[ProjectSuggestion]:
        """Group unscoped atoms by subject frequency. Returns suggestions for subjects with 3+ atoms."""
        # Get all active atoms that aren't scoped to any project
        from sqlalchemy import select

        from sulci_core.schema import KnowledgeAtomRow

        async with store._session_factory() as session:
            query = (
                select(KnowledgeAtomRow)
                .where(KnowledgeAtomRow.is_active.is_(True))
                .where((KnowledgeAtomRow.projects_json == "[]") | (KnowledgeAtomRow.projects_json.is_(None)))
            )
            result = await session.execute(query)
            rows = result.scalars().all()

        unscoped_atoms = [store._row_to_atom(r) for r in rows]
        if not unscoped_atoms:
            return []

        # Count subjects
        subject_atoms: dict[str, list[KnowledgeAtom]] = {}
        for atom in unscoped_atoms:
            if atom.subject:
                key = atom.subject.lower().strip()
                subject_atoms.setdefault(key, []).append(atom)

        # Filter to existing projects and dismissed suggestions to avoid duplicates
        existing_projects = {p.name.lower() for p in await store.list_projects_full()}
        dismissed = await store.list_dismissed_suggestions()

        suggestions: list[ProjectSuggestion] = []
        for subject, atoms in subject_atoms.items():
            if len(atoms) < SUBJECT_THRESHOLD:
                continue
            if subject in existing_projects:
                continue

            # Build a clean project name
            name = subject.replace(" ", "-").lower()
            if name in existing_projects:
                continue
            if name in dismissed or subject in dismissed:
                continue

            # Compute confidence based on atom count
            confidence = min(0.5 + (len(atoms) - SUBJECT_THRESHOLD) * 0.1, 0.95)

            # Gather atom types for description
            type_counts = Counter(a.atom_type.value for a in atoms)
            type_summary = ", ".join(f"{c} {t}(s)" for t, c in type_counts.most_common(3))

            suggestions.append(
                ProjectSuggestion(
                    name=name,
                    description=f"Auto-detected from {len(atoms)} unscoped atoms about '{subject}'",
                    atom_ids=[a.id for a in atoms],
                    confidence=confidence,
                    reason=f"{len(atoms)} atoms with subject '{subject}': {type_summary}",
                )
            )

        # Sort by confidence descending
        suggestions.sort(key=lambda s: s.confidence, reverse=True)
        return suggestions[:10]  # Cap at 10
