"""
Reader per file CSV.

Supporta delimitatori personalizzati e diverse codifiche.
Utilizza il modulo csv della libreria standard.
"""

import csv
from typing import Any

from .base import BaseReader
from dataprofiler.exceptions import DataReadError


class CsvReader(BaseReader):
    """Reader per file in formato CSV.

    Supporta diversi delimitatori (virgola, punto e virgola, tab)
    e codifiche (utf-8, latin-1, ecc.).

    Args:
        filepath: Percorso del file CSV.
        delimiter: Carattere separatore (default: ",").
        encoding: Codifica del file (default: "utf-8").

    Esempio::

        reader = CsvReader("dati.csv", delimiter=";", encoding="latin-1")
        dati = reader.read()
        print(reader.get_headers())
    """

    def __init__(
        self,
        filepath: str,
        delimiter: str = ",",
        encoding: str = "utf-8",
    ):
        super().__init__(filepath)
        self._delimiter = delimiter
        self._encoding = encoding
        self._headers: list[str] = []

    def read(self) -> list[dict[str, Any]]:
        """Legge il file CSV e restituisce lista di dizionari.

        Returns:
            Lista di dizionari dove ogni chiave è un nome di colonna.

        Raises:
            DataReadError: Se il file non può essere letto correttamente.
        """
        try:
            rows: list[dict[str, Any]] = []
            with open(self._filepath, "r", encoding=self._encoding, newline="") as f:
                reader = csv.DictReader(f, delimiter=self._delimiter)
                self._headers = list(reader.fieldnames or [])
                for row in reader:
                    # Converti valori vuoti in None per uniformità
                    clean_row = {
                        k: (v if v is not None and v.strip() != "" else None)
                        for k, v in row.items()
                    }
                    rows.append(clean_row)
            return rows
        except UnicodeDecodeError as e:
            raise DataReadError(
                f"Errore di codifica nel file '{self._filepath}'. "
                f"Prova con encoding='latin-1'. Dettaglio: {e}"
            )
        except csv.Error as e:
            raise DataReadError(
                f"Errore nella lettura del CSV '{self._filepath}': {e}"
            )

    def get_headers(self) -> list[str]:
        """Restituisce i nomi delle colonne del CSV.

        Se non ancora letto, legge solo la prima riga.

        Returns:
            Lista dei nomi delle colonne.
        """
        if not self._headers:
            try:
                with open(self._filepath, "r", encoding=self._encoding) as f:
                    reader = csv.reader(f, delimiter=self._delimiter)
                    self._headers = next(reader, [])
            except Exception as e:
                raise DataReadError(f"Impossibile leggere gli header: {e}")
        return self._headers
