"""
CSV generation utilities for invoice movement reports.
"""
import csv
import io
from typing import List, Union
from datetime import datetime, date

from .schemas import MovementItem, MovementItemDetailed, AllMovementsFilter


def generate_csv_from_movements(
    movements: List[Union[MovementItem, MovementItemDetailed]],
    filters: AllMovementsFilter
) -> str:
    """
    Generate CSV content from movement items.

    Args:
        movements: List of movement items (normal or detailed)
        filters: Filter object containing report parameters

    Returns:
        CSV content as string
    """
    output = io.StringIO()

    if filters.report_type.value.lower() == "normal":
        # Normal report
        fieldnames = [
            # Identification
            'Factura', 'Pedimento', 'FechaFactura', 'ClavePed',
            # Values
            'ValorComercialMN', 'ValorMPTemp', 'TipoCambio', 'ValorAgre',
            # Classification
            'TipoMovTemDef', 'Estatus', 'TipoExpo', 'EsCambioRegimen',
            # Dates
            'Fecha_Pago',
            # References
            'PedimentoR1', 'EDocument', 'NumOperacionVU',
            # Logistics
            'NumCaja', 'NumGafUni', 'AduanaCru',
            # Metadata
            'BaseDeDatos', 'UsuarioCap', 'UsuarioAcr'
        ]

        writer = csv.DictWriter(output, fieldnames=fieldnames, extrasaction='ignore')
        writer.writeheader()

        for movement in movements:
            row = movement.model_dump()
            # Format datetime fields
            row['FechaFactura'] = _format_datetime(row.get('FechaFactura'))
            row['Fecha_Pago'] = _format_datetime(row.get('Fecha_Pago'))

            # Format numeric fields
            row['ValorComercialMN'] = _format_decimal(row.get('ValorComercialMN'))
            row['TipoCambio'] = _format_decimal(row.get('TipoCambio'))
            row['ValorMPTemp'] = _format_decimal(row.get('ValorMPTemp'))
            row['ValorAgre'] = _format_decimal(row.get('ValorAgre'))

            writer.writerow(row)

    else:
        # Detailed report
        fieldnames = [
            # Identification
            'Linea', 'Factura', 'Pedimento', 'FechaFactura', 'ClavePed',
            # Parties
            'Proveedor', 'RFCProveedor', 'ProveedorTaxID',
            'VendidoA', 'VendidoARFC', 'VendidoATaxID',
            # Customs broker
            'AgenteAduanal', 'Patente',
            # Product
            'NumParte', 'DescripcionE', 'DescripcionI', 'CantidadIE', 'UniMed',
            # Classification
            'FraccionArancelaria', 'FraccionAmericana', 'ECCN', 'Sector', 'PaisOrigen',
            # Values
            'ValorComercialMN', 'TipoCambio', 'PesoNeto', 'PesoBruto',
            # Customs
            'TipoMovTemDef', 'Regimen', 'Aduana', 'Advalorem', 'Preferencia',
            # References
            'OrdenCompraVenta', 'Remesa', 'PedimentoR1', 'EDocument', 'NumOperacionVU',
            # Identifiers
            'Series', 'Marca', 'Modelo', 'SimboloEx',
            # Dates
            'Fecha_Pago', 'Fecha_Inicio', 'Fecha_Fin', 'FechaEmision',
            # Logistics
            'Transportista', 'NumCaja', 'NumGafUni', 'AduanaCru', 'Lote',
            # Metadata
            'Estatus', 'BaseDeDatos', 'TipoExpo', 'EsCambioRegimen', 'Pedimento18',
            'UsuarioCap', 'UsuarioAcr'
        ]

        writer = csv.DictWriter(output, fieldnames=fieldnames, extrasaction='ignore')
        writer.writeheader()

        for movement in movements:
            row = movement.model_dump()
            # Format datetime fields
            row['FechaFactura'] = _format_datetime(row.get('FechaFactura'))
            row['Fecha_Pago'] = _format_datetime(row.get('Fecha_Pago'))
            row['Fecha_Inicio'] = _format_datetime(row.get('Fecha_Inicio'))
            row['Fecha_Fin'] = _format_datetime(row.get('Fecha_Fin'))
            row['FechaEmision'] = _format_datetime(row.get('FechaEmision'))

            # Format numeric fields
            row['ValorComercialMN'] = _format_decimal(row.get('ValorComercialMN'))
            row['TipoCambio'] = _format_decimal(row.get('TipoCambio'))
            row['CantidadIE'] = _format_decimal(row.get('CantidadIE'))
            row['PesoNeto'] = _format_decimal(row.get('PesoNeto'))
            row['PesoBruto'] = _format_decimal(row.get('PesoBruto'))

            writer.writerow(row)

    csv_content = output.getvalue()
    output.close()
    return csv_content


def _format_datetime(dt) -> str:
    """Format datetime for CSV export."""
    if not dt or dt == '' or dt == '-' or dt == '0':
        return ''
    try:
        if isinstance(dt, str):
            if 'T' in dt:
                dt_obj = datetime.strptime(dt.split('T')[0], '%Y-%m-%d')
            elif len(dt) == 8 and dt.isdigit():
                dt_obj = datetime.strptime(dt, '%Y%m%d')
            elif '-' in dt:
                dt_obj = datetime.strptime(dt, '%Y-%m-%d')
            else:
                return dt
        elif isinstance(dt, (datetime, date)):
            dt_obj = dt
        else:
            return ''
        return dt_obj.strftime('%d/%m/%Y')
    except (ValueError, TypeError):
        return str(dt) if dt else ''


def _format_decimal(value, decimals: int = 2) -> str:
    """Format decimal values for CSV export."""
    if value is None:
        return ''
    try:
        return f"{float(value):.{decimals}f}"
    except (ValueError, TypeError):
        return str(value) if value else ''