# File: cpp_python_debug/core/output_formatter.py
import json
import csv
import logging
from typing import List, Dict, Any, Union, Optional

logger = logging.getLogger(__name__)


def save_to_json(data: Any, filepath: str) -> None:
    """
    Saves the given Python data structure to a JSON file.
    """
    logger.info(f"Attempting to save data to JSON file: {filepath}")
    try:
        with open(filepath, "w", encoding="utf-8") as f:
            # Salva l'intero oggetto (che può includere metadata e data)
            json.dump(data, f, indent=2, ensure_ascii=False)
        logger.info(f"Data successfully saved to JSON: {filepath}")
    except (IOError, TypeError) as e:
        logger.error(f"Error saving JSON to {filepath}: {e}", exc_info=True)
        raise
    except Exception as e:
        logger.error(f"Unexpected error saving JSON to {filepath}: {e}", exc_info=True)
        raise


def save_to_csv(
    data_to_save: Any,
    filepath: str,
    metadata: Optional[Dict[str, Any]] = None
) -> None:
    """
    Saves data to a CSV file, prepending metadata if provided.

    Args:
        data_to_save: The main data payload (e.g., list, list of lists).
        filepath: The path to the file where CSV data will be saved.
        metadata: An optional dictionary of metadata to write at the top of the file.
    """
    logger.info(f"Attempting to save data to CSV file: {filepath}")
    if metadata:
        logger.debug(f"Metadata provided for CSV: {metadata}")

    # La logica di appiattimento rimane la stessa della versione precedente,
    # ma la applichiamo solo a `data_to_save`.
    list_of_dicts_for_csv: List[Dict[str, Any]] = []
    
    is_matrix = (
        metadata and metadata.get("is_matrix") and isinstance(data_to_save, list)
    )

    if is_matrix:
        logger.debug("Flattening matrix data to coordinate format.")
        for r, row_data in enumerate(data_to_save):
            if not isinstance(row_data, list):
                logger.warning("Matrix structure is not uniform. Treating as a simple list.")
                is_matrix = False
                break
            for c, cell_data in enumerate(row_data):
                flat_row: Dict[str, Any] = {'row_idx': r, 'col_idx': c}
                if isinstance(cell_data, dict):
                    flat_row.update(cell_data)
                elif isinstance(cell_data, (str, int, float, bool, type(None))):
                    flat_row['value'] = cell_data
                else:
                    flat_row['error_value'] = str(cell_data)
                list_of_dicts_for_csv.append(flat_row)
    
    if not is_matrix:
        logger.debug("Processing as a standard list/item.")
        list_of_dicts_for_csv = []
        data_list = data_to_save if isinstance(data_to_save, list) else [data_to_save]
        for item in data_list:
            if isinstance(item, dict):
                list_of_dicts_for_csv.append(item)
            else:
                list_of_dicts_for_csv.append({'value': str(item)})

    # --- Scrittura CSV con Metadati ---
    try:
        with open(filepath, "w", newline="", encoding="utf-8") as csvfile:
            # 1. Scrivi i metadati come righe commentate
            if metadata:
                metadata_lines = [f"# {key}: {value}" for key, value in metadata.items()]
                # Aggiungi un contatore di righe di metadati per facilitare il parsing
                metadata_lines.insert(0, f"# METADATA_ROWS: {len(metadata_lines)}")
                for line in metadata_lines:
                    csvfile.write(line + "\n")

            # 2. Scrivi i dati
            if not list_of_dicts_for_csv:
                logger.warning(f"No data rows to write to CSV file: {filepath}.")
                return

            headers = set()
            for row_dict in list_of_dicts_for_csv:
                if isinstance(row_dict, dict):
                    headers.update(row_dict.keys())
            
            ordered_headers: List[str] = []
            if 'row_idx' in headers: ordered_headers.append('row_idx'); headers.remove('row_idx')
            if 'col_idx' in headers: ordered_headers.append('col_idx'); headers.remove('col_idx')
            ordered_headers.extend(sorted(list(headers)))

            logger.debug(f"Determined CSV headers: {ordered_headers}")
            
            writer = csv.DictWriter(csvfile, fieldnames=ordered_headers, restval="N/A")
            writer.writeheader()
            writer.writerows(list_of_dicts_for_csv)

        logger.info(f"Data and metadata successfully saved to CSV: {filepath}")

    except Exception as e:
        logger.error(f"Error during CSV writing to {filepath}: {e}", exc_info=True)
        raise