"""
Reader per file JSON.

Supporta file JSON contenenti un array di oggetti,
che è il formato più comune per dati tabulari in JSON.
"""

import json
from typing import Any

from .base import BaseReader
from dataprofiler.exceptions import DataReadError


class JsonReader(BaseReader):
    """Reader per file in formato JSON.

    Si aspetta un file contenente un array di oggetti JSON,
    dove ogni oggetto rappresenta una riga del dataset.

    Formato supportato::

        [
            {"nome": "Marco", "età": 22, "città": "Milano"},
            {"nome": "Laura", "età": 20, "città": "Roma"}
        ]

    Args:
        filepath: Percorso del file JSON.
        encoding: Codifica del file (default: "utf-8").

    Esempio::

        reader = JsonReader("prodotti.json")
        dati = reader.read()
    """

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

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

        Returns:
            Lista di dizionari dove ogni chiave è un campo dell'oggetto.

        Raises:
            DataReadError: Se il JSON non è valido o non è un array di oggetti.
        """
        try:
            with open(self._filepath, "r", encoding=self._encoding) as f:
                data = json.load(f)
        except json.JSONDecodeError as e:
            raise DataReadError(
                f"Il file '{self._filepath}' non contiene JSON valido: {e}"
            )
        except UnicodeDecodeError as e:
            raise DataReadError(
                f"Errore di codifica nel file '{self._filepath}': {e}"
            )

        # Verifica che sia un array di oggetti
        if not isinstance(data, list):
            raise DataReadError(
                f"Il file JSON deve contenere un array di oggetti. "
                f"Trovato: {type(data).__name__}"
            )

        if not data:
            return []

        if not isinstance(data[0], dict):
            raise DataReadError(
                f"Ogni elemento dell'array deve essere un oggetto JSON. "
                f"Trovato: {type(data[0]).__name__}"
            )

        # Raccogli tutti gli header (unione di tutte le chiavi)
        all_keys: list[str] = []
        seen: set[str] = set()
        for row in data:
            for key in row.keys():
                if key not in seen:
                    all_keys.append(key)
                    seen.add(key)
        self._headers = all_keys

        # Normalizza: ogni riga ha tutte le chiavi
        rows: list[dict[str, Any]] = []
        for row in data:
            normalized = {}
            for key in self._headers:
                value = row.get(key)
                # Converti stringhe vuote in None
                if isinstance(value, str) and value.strip() == "":
                    value = None
                normalized[key] = value
            rows.append(normalized)

        return rows

    def get_headers(self) -> list[str]:
        """Restituisce i nomi dei campi trovati nel JSON.

        Returns:
            Lista dei nomi dei campi (unione di tutti gli oggetti).
        """
        if not self._headers:
            self.read()
        return self._headers
