"""
Chunk Validator Module

This module provides comprehensive quality validation for document chunks,
ensuring proper splitting, data integrity, and semantic coherence.

Key Features:
    - Size validation (min/max chunk size)
    - Content validation (empty/whitespace detection)
    - Semantic coherence checking
    - Structure quality assessment
    - Batch validation
    - Confidence-based filtering

Main Classes:
    - ChunkValidator: Main validation coordinator
    - ValidationResult: Validation result representation dataclass

Example Usage:
    >>> from semantica.split import ChunkValidator
    >>> validator = ChunkValidator(min_size=10, max_size=10000)
    >>> result = validator.validate(chunk)
    >>> if result.valid:
    ...     print(f"Quality score: {result.score}")
    >>> valid_chunks = validator.filter_valid_chunks(chunks)

Author: Semantica Contributors
License: MIT
"""

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

from ..utils.exceptions import ProcessingError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
from .semantic_chunker import Chunk


@dataclass
class ValidationResult:
    """Validation result representation."""

    valid: bool
    score: float
    errors: List[str] = field(default_factory=list)
    warnings: List[str] = field(default_factory=list)
    metrics: Dict[str, Any] = field(default_factory=dict)


class ChunkValidator:
    """Chunk validator for quality assessment."""

    def __init__(self, **config):
        """
        Initialize chunk validator.

        Args:
            **config: Configuration options:
                - min_size: Minimum chunk size in characters (default: 10)
                - max_size: Maximum chunk size in characters (default: 10000)
                - min_score: Minimum quality score (default: 0.5)
        """
        self.logger = get_logger("chunk_validator")
        self.config = config
        self.progress_tracker = get_progress_tracker()

        self.min_size = config.get("min_size", 10)
        self.max_size = config.get("max_size", 10000)
        self.min_score = config.get("min_score", 0.5)

    def validate(self, chunk: Chunk, **options) -> ValidationResult:
        """
        Validate a single chunk.

        Args:
            chunk: Chunk to validate
            **options: Validation options

        Returns:
            ValidationResult: Validation result
        """
        tracking_id = self.progress_tracker.start_tracking(
            module="split", submodule="ChunkValidator", message="Validating chunk"
        )

        try:
            errors = []
            warnings = []
            metrics = {}

            # Size validation
            self.progress_tracker.update_tracking(
                tracking_id, message="Validating chunk size..."
            )
            chunk_size = len(chunk.text)
            metrics["size"] = chunk_size

            if chunk_size < self.min_size:
                errors.append(f"Chunk too small: {chunk_size} < {self.min_size}")

            if chunk_size > self.max_size:
                errors.append(f"Chunk too large: {chunk_size} > {self.max_size}")

            # Content validation
            if not chunk.text.strip():
                errors.append("Chunk is empty or whitespace only")

            # Coherence validation
            self.progress_tracker.update_tracking(
                tracking_id, message="Checking semantic coherence..."
            )
            coherence_score = self._check_coherence(chunk.text)
            metrics["coherence"] = coherence_score

            if coherence_score < 0.3:
                warnings.append(f"Low semantic coherence: {coherence_score:.2f}")

            # Structure validation
            self.progress_tracker.update_tracking(
                tracking_id, message="Checking structure..."
            )
            structure_score = self._check_structure(chunk.text)
            metrics["structure"] = structure_score

            # Calculate overall score
            score = self._calculate_score(
                chunk_size, coherence_score, structure_score, errors
            )
            metrics["overall_score"] = score

            valid = len(errors) == 0 and score >= self.min_score

            result = ValidationResult(
                valid=valid,
                score=score,
                errors=errors,
                warnings=warnings,
                metrics=metrics,
            )

            self.progress_tracker.stop_tracking(
                tracking_id,
                status="completed",
                message=f"Validation complete: {'valid' if valid else 'invalid'}",
            )
            return result

        except Exception as e:
            self.progress_tracker.stop_tracking(
                tracking_id, status="failed", message=str(e)
            )
            raise

    def validate_batch(self, chunks: List[Chunk], **options) -> Dict[str, Any]:
        """
        Validate multiple chunks.

        Args:
            chunks: List of chunks to validate
            **options: Validation options

        Returns:
            dict: Batch validation results
        """
        results = []
        valid_count = 0
        total_score = 0.0

        for chunk in chunks:
            result = self.validate(chunk, **options)
            results.append(result)

            if result.valid:
                valid_count += 1
            total_score += result.score

        avg_score = total_score / len(chunks) if chunks else 0.0

        return {
            "total_chunks": len(chunks),
            "valid_chunks": valid_count,
            "invalid_chunks": len(chunks) - valid_count,
            "average_score": avg_score,
            "results": results,
            "summary": {
                "validity_rate": valid_count / len(chunks) if chunks else 0.0,
                "average_coherence": sum(r.metrics.get("coherence", 0) for r in results)
                / len(results)
                if results
                else 0.0,
                "average_structure": sum(r.metrics.get("structure", 0) for r in results)
                / len(results)
                if results
                else 0.0,
            },
        }

    def _check_coherence(self, text: str) -> float:
        """
        Check semantic coherence of text.

        Args:
            text: Text to check

        Returns:
            float: Coherence score (0-1)
        """
        if not text:
            return 0.0

        score = 1.0

        # Check sentence completeness
        sentences = text.split(".")
        incomplete_sentences = sum(
            1 for s in sentences if s.strip() and not s.strip()[-1] in ".!?"
        )
        if sentences:
            completeness = 1.0 - (incomplete_sentences / len(sentences))
            score *= completeness

        # Check for very short fragments
        words = text.split()
        if len(words) < 3:
            score *= 0.5

        # Check word repetition (high repetition = lower coherence)
        if len(words) > 10:
            unique_words = len(set(word.lower() for word in words))
            diversity = unique_words / len(words)
            score *= 0.5 + diversity * 0.5

        return max(0.0, min(1.0, score))

    def _check_structure(self, text: str) -> float:
        """
        Check text structure quality.

        Args:
            text: Text to check

        Returns:
            float: Structure score (0-1)
        """
        if not text:
            return 0.0

        score = 1.0

        # Check for proper capitalization
        first_char = text.strip()[0] if text.strip() else ""
        if first_char and first_char.islower():
            score *= 0.9

        # Check for balanced punctuation
        sentences = [s.strip() for s in text.split(".") if s.strip()]
        if len(sentences) > 1:
            # More sentences = better structure
            structure_factor = min(1.0, len(sentences) / 5.0)
            score *= 0.7 + structure_factor * 0.3

        # Check for whitespace issues
        if "  " in text or "\t\t" in text:
            score *= 0.9

        return max(0.0, min(1.0, score))

    def _calculate_score(
        self, size: int, coherence: float, structure: float, errors: List[str]
    ) -> float:
        """
        Calculate overall validation score.

        Args:
            size: Chunk size
            coherence: Coherence score
            structure: Structure score
            errors: List of errors

        Returns:
            float: Overall score (0-1)
        """
        # Start with base score
        score = 1.0

        # Apply size penalty
        if size < self.min_size or size > self.max_size:
            score *= 0.5

        # Weighted combination of coherence and structure
        score = score * (0.6 * coherence + 0.4 * structure)

        # Penalize for errors
        score *= max(0.0, 1.0 - len(errors) * 0.2)

        return max(0.0, min(1.0, score))

    def filter_valid_chunks(self, chunks: List[Chunk], **options) -> List[Chunk]:
        """
        Filter chunks to only include valid ones.

        Args:
            chunks: List of chunks to filter
            **options: Validation options

        Returns:
            list: List of valid chunks
        """
        valid_chunks = []

        for chunk in chunks:
            result = self.validate(chunk, **options)
            if result.valid:
                valid_chunks.append(chunk)

        return valid_chunks
