"""Test per gli analyzer (Numeric, Text, DateTime, Boolean)."""

import pytest
from dataprofiler.analyzers import (
    NumericAnalyzer, TextAnalyzer, DateTimeAnalyzer, BooleanAnalyzer,
)
from dataprofiler.models.column_profile import ColumnType


class TestNumericAnalyzer:
    """Test per NumericAnalyzer."""

    def setup_method(self):
        self.analyzer = NumericAnalyzer()

    def test_can_analyze_numeric(self, sample_numeric_values):
        assert self.analyzer.can_analyze(sample_numeric_values, "col") is True

    def test_cannot_analyze_text(self, sample_text_values):
        assert self.analyzer.can_analyze(sample_text_values, "col") is False

    def test_analyze_returns_correct_type(self, sample_numeric_values):
        profile = self.analyzer.analyze(sample_numeric_values, "prezzo")
        assert profile.dtype == ColumnType.NUMERIC

    def test_analyze_counts_missing(self, sample_numeric_values):
        profile = self.analyzer.analyze(sample_numeric_values, "prezzo")
        assert profile.missing_count == 2  # None e ""

    def test_analyze_calculates_stats(self, sample_numeric_values):
        profile = self.analyzer.analyze(sample_numeric_values, "prezzo")
        assert profile.stats["media"] == 30.0  # (10+20+30+40+50)/5
        assert profile.stats["min"] == 10.0
        assert profile.stats["max"] == 50.0
        assert profile.stats["mediana"] == 30.0

    def test_analyze_empty_column(self):
        profile = self.analyzer.analyze([None, None, ""], "vuoto")
        assert profile.stats == {}
        assert profile.missing_count == 3

    def test_can_analyze_empty(self):
        assert self.analyzer.can_analyze([None, None], "col") is False

    def test_unique_count(self):
        values = ["10", "20", "10", "30", "20"]
        profile = self.analyzer.analyze(values, "col")
        assert profile.unique_count == 3


class TestTextAnalyzer:
    """Test per TextAnalyzer."""

    def setup_method(self):
        self.analyzer = TextAnalyzer()

    def test_can_analyze_text(self, sample_text_values):
        assert self.analyzer.can_analyze(sample_text_values, "col") is True

    def test_cannot_analyze_numeric(self, sample_numeric_values):
        assert self.analyzer.can_analyze(sample_numeric_values, "col") is False

    def test_analyze_returns_correct_type(self, sample_text_values):
        profile = self.analyzer.analyze(sample_text_values, "citta")
        assert profile.dtype == ColumnType.TEXT

    def test_analyze_counts_missing(self, sample_text_values):
        profile = self.analyzer.analyze(sample_text_values, "citta")
        assert profile.missing_count == 1

    def test_analyze_top_5(self, sample_text_values):
        profile = self.analyzer.analyze(sample_text_values, "citta")
        top5 = profile.stats["top_5_valori"]
        assert "Milano" in top5
        assert top5["Milano"] == 2

    def test_analyze_lengths(self, sample_text_values):
        profile = self.analyzer.analyze(sample_text_values, "citta")
        assert profile.stats["lunghezza_min"] > 0
        assert profile.stats["lunghezza_max"] >= profile.stats["lunghezza_min"]

    def test_can_analyze_empty_is_true(self):
        """TextAnalyzer è il fallback, accetta anche colonne vuote."""
        assert self.analyzer.can_analyze([None, None], "col") is True


class TestDateTimeAnalyzer:
    """Test per DateTimeAnalyzer."""

    def setup_method(self):
        self.analyzer = DateTimeAnalyzer()

    def test_can_analyze_dates(self, sample_date_values):
        assert self.analyzer.can_analyze(sample_date_values, "col") is True

    def test_cannot_analyze_text(self, sample_text_values):
        assert self.analyzer.can_analyze(sample_text_values, "col") is False

    def test_analyze_returns_correct_type(self, sample_date_values):
        profile = self.analyzer.analyze(sample_date_values, "data")
        assert profile.dtype == ColumnType.DATETIME

    def test_analyze_date_range(self, sample_date_values):
        profile = self.analyzer.analyze(sample_date_values, "data")
        assert profile.stats["data_min"] == "2024-01-15"
        assert profile.stats["data_max"] == "2024-09-10"
        assert profile.stats["range_giorni"] > 0

    def test_italian_date_format(self):
        values = ["15/01/2024", "20/03/2024", "01/06/2024"]
        assert self.analyzer.can_analyze(values, "data") is True
        profile = self.analyzer.analyze(values, "data")
        assert profile.stats["formato_comune"] == "%d/%m/%Y"

    def test_does_not_mistake_numbers_for_dates(self):
        values = ["100", "200", "300", "400"]
        assert self.analyzer.can_analyze(values, "col") is False


class TestBooleanAnalyzer:
    """Test per BooleanAnalyzer."""

    def setup_method(self):
        self.analyzer = BooleanAnalyzer()

    def test_can_analyze_booleans(self, sample_bool_values):
        assert self.analyzer.can_analyze(sample_bool_values, "col") is True

    def test_cannot_analyze_text(self, sample_text_values):
        assert self.analyzer.can_analyze(sample_text_values, "col") is False

    def test_analyze_returns_correct_type(self, sample_bool_values):
        profile = self.analyzer.analyze(sample_bool_values, "attivo")
        assert profile.dtype == ColumnType.BOOLEAN

    def test_analyze_counts(self, sample_bool_values):
        profile = self.analyzer.analyze(sample_bool_values, "attivo")
        assert profile.stats["true_count"] == 3
        assert profile.stats["false_count"] == 2
        assert profile.stats["percentuale_true"] == 60.0

    def test_various_boolean_formats(self):
        values = ["true", "false", "1", "0", "yes", "no"]
        assert self.analyzer.can_analyze(values, "col") is True
        profile = self.analyzer.analyze(values, "col")
        assert profile.stats["true_count"] == 3
        assert profile.stats["false_count"] == 3
