"""
Data Quality Service.

This module provides functions for computing QualityDelta
from Django model instances and generating coaching advice.

Usage:
    from lightwave.data_quality.quality_service import (
        compute_task_quality,
        compute_sprint_quality,
        compute_document_quality,
        batch_compute_quality,
        generate_batch_coaching,
    )

    # Compute quality for a single task
    task = Task.objects.get(id="...")
    delta = compute_task_quality(task)

    # Generate coaching advice
    advice = generate_coaching(delta)
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from lightwave.schema.pydantic.models.ideal_state import (
    CoachingAdvice,
    IdealDocumentSchema,
    IdealSprintSchema,
    IdealTaskSchema,
    QualityDelta,
    generate_coaching,
)

if TYPE_CHECKING:
    pass


# =============================================================================
# QUALITY COMPUTATION
# =============================================================================


def compute_task_quality(task: Any) -> QualityDelta:
    """
    Compute QualityDelta for a Task-like object.

    This service function bridges Django models to Pydantic validation.

    Args:
        task: Django Task model instance or task-like object

    Returns:
        QualityDelta with gaps, constraint violations, and scores
    """
    return IdealTaskSchema.compute_delta(task)


def compute_sprint_quality(sprint: Any) -> QualityDelta:
    """
    Compute QualityDelta for a Sprint-like object.

    Args:
        sprint: Django Sprint model instance or sprint-like object

    Returns:
        QualityDelta with gaps, constraint violations, and scores
    """
    return IdealSprintSchema.compute_delta(sprint)


def compute_document_quality(document: Any) -> QualityDelta:
    """
    Compute QualityDelta for a Document-like object.

    Args:
        document: Django Document model instance or document-like object

    Returns:
        QualityDelta with gaps, constraint violations, and scores
    """
    return IdealDocumentSchema.compute_delta(document)


def batch_compute_quality(entities: list[Any], entity_type: str) -> list[QualityDelta]:
    """
    Batch compute QualityDelta for a list of entities.

    Args:
        entities: List of Django model instances
        entity_type: One of 'task', 'sprint', 'document'

    Returns:
        List of QualityDelta objects

    Raises:
        ValueError: If entity_type is unknown
    """
    compute_funcs = {
        "task": compute_task_quality,
        "sprint": compute_sprint_quality,
        "document": compute_document_quality,
    }

    if entity_type not in compute_funcs:
        raise ValueError(f"Unknown entity_type: {entity_type}")

    return [compute_funcs[entity_type](entity) for entity in entities]


def get_unhealthy_entities(deltas: list[QualityDelta]) -> list[QualityDelta]:
    """
    Filter to only unhealthy entities.

    An entity is unhealthy if it has required gaps or constraint violations.

    Args:
        deltas: List of QualityDelta objects

    Returns:
        Filtered list containing only unhealthy entities
    """
    return [d for d in deltas if not d.is_healthy]


def generate_batch_coaching(
    deltas: list[QualityDelta],
    max_suggestions_per_entity: int = 3,
) -> dict[str, list[CoachingAdvice]]:
    """
    Generate coaching advice for multiple entities.

    Only generates coaching for unhealthy entities.

    Args:
        deltas: List of QualityDelta objects
        max_suggestions_per_entity: Maximum suggestions per entity

    Returns:
        Dict mapping entity_id to list of CoachingAdvice
    """
    return {
        delta.entity_id: generate_coaching(delta, max_suggestions=max_suggestions_per_entity)
        for delta in deltas
        if not delta.is_healthy
    }


# =============================================================================
# DJANGO INTEGRATION
# =============================================================================


def compute_quality_for_queryset(
    queryset: Any,
    entity_type: str,
) -> list[QualityDelta]:
    """
    Compute quality for a Django QuerySet.

    Args:
        queryset: Django QuerySet of entities
        entity_type: One of 'task', 'sprint', 'document'

    Returns:
        List of QualityDelta objects
    """
    entities = list(queryset)
    return batch_compute_quality(entities, entity_type)


def audit_sprint_tasks(sprint: Any) -> dict[str, Any]:
    """
    Audit all tasks in a sprint for data quality.

    Args:
        sprint: Django Sprint model instance

    Returns:
        Dict with sprint quality, task deltas, and coaching
    """
    # Compute sprint quality
    sprint_delta = compute_sprint_quality(sprint)

    # Compute task quality for all tasks in sprint
    tasks = list(sprint.tasks.all())
    task_deltas = batch_compute_quality(tasks, "task")

    # Get unhealthy tasks
    unhealthy = get_unhealthy_entities(task_deltas)

    # Generate coaching
    coaching = generate_batch_coaching(task_deltas)

    # Calculate aggregate metrics
    task_health_scores = [d.completeness_score for d in task_deltas]
    avg_task_health = sum(task_health_scores) / len(task_health_scores) if task_health_scores else 0

    return {
        "sprint_id": str(sprint.id),
        "sprint_name": sprint.name,
        "sprint_delta": sprint_delta.to_dict(),
        "task_count": len(tasks),
        "healthy_task_count": len(tasks) - len(unhealthy),
        "unhealthy_task_count": len(unhealthy),
        "average_task_health": float(avg_task_health),
        "unhealthy_task_ids": [d.entity_id for d in unhealthy],
        "coaching_by_task": {task_id: [a.to_dict() for a in advice_list] for task_id, advice_list in coaching.items()},
    }
