"""Test per i reader (CsvReader, JsonReader, ReaderFactory)."""

import pytest
from dataprofiler.readers import ReaderFactory, CsvReader, JsonReader
from dataprofiler.exceptions import FileNotFoundError, UnsupportedFormatError


class TestReaderFactory:
    """Test per la ReaderFactory (pattern Factory)."""

    def test_create_csv_reader(self, csv_path):
        reader = ReaderFactory.create(csv_path)
        assert isinstance(reader, CsvReader)

    def test_create_json_reader(self, json_path):
        reader = ReaderFactory.create(json_path)
        assert isinstance(reader, JsonReader)

    def test_unsupported_format(self, tmp_output):
        fake = tmp_output / "dati.xyz"
        fake.write_text("nope")
        with pytest.raises(UnsupportedFormatError):
            ReaderFactory.create(str(fake))

    def test_file_not_found(self):
        with pytest.raises(FileNotFoundError):
            ReaderFactory.create("/file/inesistente.csv")

    def test_supported_formats(self):
        formats = ReaderFactory.supported_formats()
        assert ".csv" in formats
        assert ".json" in formats
        assert ".xlsx" in formats

    def test_register_custom_reader(self, csv_path):
        ReaderFactory.register(".tsv", CsvReader)
        assert ".tsv" in ReaderFactory.supported_formats()
        # Pulizia
        del ReaderFactory._registry[".tsv"]


class TestCsvReader:
    """Test per il CsvReader."""

    def test_read_returns_list(self, csv_path):
        reader = CsvReader(csv_path)
        data = reader.read()
        assert isinstance(data, list)
        assert len(data) == 15

    def test_read_returns_dicts(self, csv_path):
        reader = CsvReader(csv_path)
        data = reader.read()
        assert isinstance(data[0], dict)
        assert "nome" in data[0]

    def test_get_headers(self, csv_path):
        reader = CsvReader(csv_path)
        headers = reader.get_headers()
        assert "id" in headers
        assert "nome" in headers
        assert "eta" in headers

    def test_missing_values_become_none(self, csv_path):
        reader = CsvReader(csv_path)
        data = reader.read()
        # Giuseppe Verdi ha eta mancante
        giuseppe = [r for r in data if r["nome"] == "Giuseppe"][0]
        assert giuseppe["eta"] is None

    def test_custom_delimiter(self, tmp_output):
        csv_file = tmp_output / "test.csv"
        csv_file.write_text("a;b;c\n1;2;3\n4;5;6")
        reader = CsvReader(str(csv_file), delimiter=";")
        data = reader.read()
        assert len(data) == 2
        assert data[0]["a"] == "1"

    def test_file_size(self, csv_path):
        reader = CsvReader(csv_path)
        assert reader.file_size > 0


class TestJsonReader:
    """Test per il JsonReader."""

    def test_read_returns_list(self, json_path):
        reader = JsonReader(json_path)
        data = reader.read()
        assert isinstance(data, list)
        assert len(data) == 12

    def test_read_returns_dicts(self, json_path):
        reader = JsonReader(json_path)
        data = reader.read()
        assert isinstance(data[0], dict)
        assert "codice" in data[0]

    def test_get_headers(self, json_path):
        reader = JsonReader(json_path)
        reader.read()
        headers = reader.get_headers()
        assert "nome" in headers
        assert "prezzo" in headers

    def test_invalid_json(self, tmp_output):
        bad_file = tmp_output / "bad.json"
        bad_file.write_text("non è json valido")
        reader = JsonReader(str(bad_file))
        from dataprofiler.exceptions import DataReadError
        with pytest.raises(DataReadError):
            reader.read()

    def test_non_array_json(self, tmp_output):
        obj_file = tmp_output / "obj.json"
        obj_file.write_text('{"chiave": "valore"}')
        reader = JsonReader(str(obj_file))
        from dataprofiler.exceptions import DataReadError
        with pytest.raises(DataReadError):
            reader.read()
