"""
Classe base astratta per i reader di file.

Definisce l'interfaccia che tutti i reader concreti devono implementare.
Ogni reader è responsabile di leggere un formato specifico e restituire
i dati in un formato unificato (lista di dizionari).
"""

from abc import ABC, abstractmethod
from typing import Any
import os

from dataprofiler.exceptions import FileNotFoundError


class BaseReader(ABC):
    """Classe base astratta per tutti i reader.

    Ogni reader concreto deve implementare:
        - read(): legge il file e restituisce i dati
        - get_headers(): restituisce i nomi delle colonne

    Args:
        filepath: Percorso del file da leggere.

    Raises:
        FileNotFoundError: Se il file non esiste.
    """

    def __init__(self, filepath: str):
        self._filepath = filepath
        self._validate_file()

    def _validate_file(self) -> None:
        """Verifica che il file esista e sia accessibile.

        Raises:
            FileNotFoundError: Se il file non esiste.
        """
        if not os.path.exists(self._filepath):
            raise FileNotFoundError(f"File non trovato: {self._filepath}")
        if not os.path.isfile(self._filepath):
            raise FileNotFoundError(f"Il percorso non è un file: {self._filepath}")

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

        Ogni dizionario rappresenta una riga, con le chiavi
        corrispondenti ai nomi delle colonne.

        Returns:
            Lista di dizionari (una riga = un dizionario).
        """
        ...

    @abstractmethod
    def get_headers(self) -> list[str]:
        """Restituisce l'elenco dei nomi delle colonne.

        Returns:
            Lista di stringhe con i nomi delle colonne.
        """
        ...

    @property
    def filepath(self) -> str:
        """Percorso del file."""
        return self._filepath

    @property
    def file_size(self) -> int:
        """Dimensione del file in byte."""
        return os.path.getsize(self._filepath)
