package internal

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"time"
)

var (
	ErrEmptyNIF        = errors.New("NIF cannot be empty")
	ErrInvalidNIF      = errors.New("invalid NIF format")
	ErrEmptyNumSerie   = errors.New("number series cannot be empty")
	ErrInvalidFecha    = errors.New("invalid date format, expected dd-mm-yyyy")
	ErrInvalidTipo     = errors.New("invalid invoice type")
	ErrInvalidImporte  = errors.New("invalid amount format")
	ErrEmptyNombre     = errors.New("business name cannot be empty")
	ErrInvalidIVACampo = errors.New("invalid IVA field: must be numeric")
)

// Empresa/CIF: letra + 7 dígitos + letra o dígito (A1234567B, B12345678)
// Autónomo/NIF: 8 dígitos + letra (53950250R)
var nifRegex = regexp.MustCompile(`^([A-Z]\d{7}[A-Z0-9]|\d{8}[A-Z])$`)
var tipoFacturaValidos = map[string]bool{
	"F1": true, "F2": true,
	"R1": true, "R2": true, "R3": true, "R4": true, "R5": true,
}

type InvoiceInput struct {
	Tipo    string       `json:"tipo"`
	Factura FacturaInput `json:"factura"`
	Sistema SistemaInput `json:"sistema"`
}

type FacturaInput struct {
	EmisorNIF       string             `json:"emisor_nif"`
	EmisorNombre    string             `json:"emisor_nombre"`
	NumSerie        string             `json:"num_serie"`
	FechaExpedicion string             `json:"fecha_expedicion"`
	TipoFactura     string             `json:"tipo_factura"`
	Descripcion     string             `json:"descripcion"`
	Destinatario    *DestinatarioInput `json:"destinatario,omitempty"`
	IVA             []IVAInput         `json:"iva"`
	ImporteTotal    float64            `json:"importe_total"`
}

type DestinatarioInput struct {
	Nombre string `json:"nombre"`
	NIF    string `json:"nif"`
}

type IVAInput struct {
	Base  float64 `json:"base"`
	Cuota float64 `json:"cuota"`
	Tipo  float64 `json:"tipo"`
}

type SistemaInput struct {
	Nombre       string `json:"nombre"`
	NIFProveedor string `json:"nif_proveedor"`
	Version      string `json:"version"`
}

type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

func (e *ValidationError) Error() string {
	return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

func ValidateInvoiceInput(in *InvoiceInput) []error {
	var errs []error

	if in.Tipo == "" {
		errs = append(errs, &ValidationError{"tipo", "operation type is required"})
	} else if in.Tipo != "alta" && in.Tipo != "anulacion" {
		errs = append(errs, &ValidationError{"tipo", "must be 'alta' or 'anulacion'"})
	}

	if in.Factura.EmisorNIF == "" {
		errs = append(errs, &ValidationError{"factura.emisor_nif", "cannot be empty"})
	} else if !isValidNIF(in.Factura.EmisorNIF) {
		errs = append(errs, &ValidationError{"factura.emisor_nif", "invalid NIF format"})
	}

	if in.Factura.NumSerie == "" {
		errs = append(errs, &ValidationError{"factura.num_serie", "cannot be empty"})
	}

	if in.Factura.FechaExpedicion == "" {
		errs = append(errs, &ValidationError{"factura.fecha_expedicion", "cannot be empty"})
	} else if !isValidDate(in.Factura.FechaExpedicion) {
		errs = append(errs, &ValidationError{"factura.fecha_expedicion", "invalid format, expected dd-mm-yyyy"})
	}

	if in.Factura.TipoFactura == "" {
		errs = append(errs, &ValidationError{"factura.tipo_factura", "cannot be empty"})
	} else if !tipoFacturaValidos[in.Factura.TipoFactura] {
		errs = append(errs, &ValidationError{"factura.tipo_factura", "invalid invoice type"})
	}

	if len(in.Factura.IVA) == 0 {
		errs = append(errs, &ValidationError{"factura.iva", "at least one IVA entry is required"})
	}

	for i, iva := range in.Factura.IVA {
		if iva.Base < 0 {
			errs = append(errs, &ValidationError{fmt.Sprintf("factura.iva[%d].base", i), "must be positive"})
		}
		if iva.Cuota < 0 {
			errs = append(errs, &ValidationError{fmt.Sprintf("factura.iva[%d].cuota", i), "must be positive"})
		}
		if iva.Tipo < 0 {
			errs = append(errs, &ValidationError{fmt.Sprintf("factura.iva[%d].tipo", i), "must be positive"})
		}
	}

	if in.Factura.ImporteTotal <= 0 {
		errs = append(errs, &ValidationError{"factura.importe_total", "must be greater than 0"})
	}

	// Destinatario es opcional, no se valida NIF
	_ = in.Factura.Destinatario

	if in.Sistema.Nombre == "" {
		errs = append(errs, &ValidationError{"sistema.nombre", "cannot be empty"})
	}
	if in.Sistema.NIFProveedor == "" {
		errs = append(errs, &ValidationError{"sistema.nif_proveedor", "cannot be empty"})
	}
	if in.Sistema.Version == "" {
		errs = append(errs, &ValidationError{"sistema.version", "cannot be empty"})
	}

	return errs
}

func isValidNIF(nif string) bool {
	if len(nif) != 9 {
		return false
	}
	return nifRegex.MatchString(nif)
}

func isValidDate(date string) bool {
	_, err := time.Parse("02-01-2006", date)
	return err == nil
}

func ParseFloat(s string) (float64, error) {
	if s == "" {
		return 0, ErrInvalidImporte
	}
	return strconv.ParseFloat(s, 64)
}
