package internal

import (
	"encoding/json"
	"fmt"
	"log"
	"time"

	"VerifactuMidAPI/internal/formats"
	"VerifactuMidAPI/verifactu"
)

type FacturaService struct {
	hashStorage LastRecordStorage
	verifactu   *verifactu.Client
}

func NewFacturaService(storage LastRecordStorage) *FacturaService {
	return &FacturaService{
		hashStorage: storage,
	}
}

func (s *FacturaService) SetVerifactuClient(client *verifactu.Client) {
	s.verifactu = client
}

func (s *FacturaService) ReloadCertificate(path, password string) error {
	if s.verifactu == nil {
		return fmt.Errorf("verifactu client not initialized")
	}
	return s.verifactu.SetCertificate(path, password)
}

type AltaOutput struct {
	Success bool   `json:"success"`
	CSV     string `json:"csv,omitempty"`
	Estado  string `json:"estado,omitempty"`
	Error   string `json:"error,omitempty"`
}

func (s *FacturaService) ProcessAlta(raw json.RawMessage) (*AltaOutput, error) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("PANIC: %v", r)
		}
	}()

	result, formatName, err := formats.TransformAuto(raw)
	if err != nil {
		return &AltaOutput{
			Success: false,
			Error:   "transform_error: " + err.Error(),
		}, nil
	}

	log.Printf("[Transform] formato=%s NumSerie=%q Fecha=%q Total=%.2f IVA=%d tramos",
		formatName, result.NumSerie, result.FechaExpedicion, result.ImporteTotal, len(result.IVA))

	if s.verifactu != nil {
		if result.EmisorNIF == "" {
			nif, nombre := s.verifactu.CertSubject()
			result.EmisorNIF = nif
			if result.EmisorNombre == "" {
				result.EmisorNombre = nombre
			}
		}
		if result.Sistema.NIFProveedor == "" {
			result.Sistema.NIFProveedor = result.EmisorNIF
		}
	}
	if result.Sistema.Nombre == "" {
		result.Sistema.Nombre = "VerifactuMidAPI"
	}
	if result.Sistema.Version == "" {
		result.Sistema.Version = "1.0"
	}

	log.Printf("[Emisor] NIF=%q Nombre=%q", result.EmisorNIF, result.EmisorNombre)
	log.Printf("[Sistema] Nombre=%q NIFProveedor=%q Version=%q", result.Sistema.Nombre, result.Sistema.NIFProveedor, result.Sistema.Version)

	return s.processInvoiceData(result)
}

func (s *FacturaService) processInvoiceData(result *formats.TransformResult) (*AltaOutput, error) {
	fecha, _ := time.Parse("02-01-2006", result.FechaExpedicion)

	ivaList := make([]IVARegularizacion, len(result.IVA))
	for i, v := range result.IVA {
		ivaList[i] = IVARegularizacion{
			Base:         v.Base,
			Cuota:        v.Cuota,
			Tipo:         v.Tipo,
			ClaveRegimen: "01",
			Calificacion: "S1",
		}
	}

	cuotaTotal := 0.0
	for _, v := range result.IVA {
		cuotaTotal += v.Cuota
	}

	var dest *Destinatario
	if result.Destinatario != nil {
		dest = &Destinatario{
			Nombre: result.Destinatario.Nombre,
			NIF:    result.Destinatario.NIF,
		}
	}

	data := &InvoiceData{
		Tipo:         "alta",
		EmisorNIF:    result.EmisorNIF,
		NumSerie:     result.NumSerie,
		Fecha:        fecha,
		TipoFactura:  result.TipoFactura,
		Descripcion:  result.Descripcion,
		Destinatario: dest,
		IVA:          ivaList,
		CuotaTotal:   cuotaTotal,
		ImporteTotal: result.ImporteTotal,
		Sistema: Sistema{
			Nombre:            result.Sistema.Nombre,
			NIFProveedor:      result.Sistema.NIFProveedor,
			NombreSistema:     result.Sistema.Nombre,
			IDSistema:         "01",
			Version:           result.Sistema.Version,
			NumeroInstalacion: "1",
			TipoUsoVerifactu:  "S",
			TipoUsoMultiOT:    "N",
			IndicadorMultiOT:  "N",
		},
		FechaGen: time.Now(),
	}

	var prevHash, prevNumSerie string
	var prevFecha time.Time
	if s.hashStorage != nil {
		record, err := s.hashStorage.GetLastRecord(result.EmisorNIF)
		if err != nil {
			return &AltaOutput{
				Success: false,
				Error:   "hash_storage_error",
			}, nil
		}
		if record != nil {
			prevHash = record.Huella
			prevNumSerie = record.NumSerie
			prevFecha = record.Fecha
		}
	}

	hashService := NewHashService()
	currentHash := hashService.CalculateHash(data, prevHash)

	now := time.Now()
	lastRecord := &LastRecord{
		EmisorNIF: data.EmisorNIF,
		NumSerie:  data.NumSerie,
		Fecha:     data.Fecha,
		Huella:    currentHash,
		FechaGen:  now,
	}

	data.Huella = currentHash
	data.FechaGen = now

	altaData := verifactu.AltaData{
		EmisorNombre:       result.EmisorNombre,
		EmisorNIF:          data.EmisorNIF,
		NumSerie:           data.NumSerie,
		FechaExpedicion:    data.Fecha,
		TipoFactura:        data.TipoFactura,
		Descripcion:        data.Descripcion,
		DestinatarioNombre: destNombre(data.Destinatario),
		DestinatarioNIF:    destNIF(data.Destinatario),
		IVA:                toIVAData(data.IVA),
		CuotaTotal:         data.CuotaTotal,
		ImporteTotal:       data.ImporteTotal,
		Sistema: verifactu.SistemaData{
			Nombre:            data.Sistema.Nombre,
			NIFProveedor:      data.Sistema.NIFProveedor,
			NombreSistema:     data.Sistema.NombreSistema,
			Version:           data.Sistema.Version,
			NumeroInstalacion: data.Sistema.NumeroInstalacion,
			TipoUsoVerifactu:  data.Sistema.TipoUsoVerifactu,
		},
		Huella:       currentHash,
		PrevHash:     prevHash,
		PrevNumSerie: prevNumSerie,
		PrevFecha:    prevFecha,
		FechaGen:     data.FechaGen,
	}

	if s.verifactu == nil {
		return &AltaOutput{
			Success: false,
			Error:   "verifactu_not_configured: no hay certificado registrado",
		}, nil
	}

	log.Printf("Sending to AEAT...")
	resp, err := s.verifactu.SendAlta(altaData)
	if err != nil {
		log.Printf("AEAT error: %v", err)
		return &AltaOutput{
			Success: false,
			Error:   "aeat_connection_error: " + err.Error(),
		}, nil
	}

	if resp.Body.Fault != nil {
		log.Printf("AEAT fault: %v", resp.Body.Fault.FaultString)
		return &AltaOutput{
			Success: false,
			Error:   "aeat_fault: " + resp.Body.Fault.FaultString,
		}, nil
	}

	if resp.Body.Respuesta == nil {
		return &AltaOutput{
			Success: false,
			Error:   "aeat_error: respuesta vacía",
		}, nil
	}

	estado := resp.Body.Respuesta.EstadoEnvio
	csv := resp.Body.Respuesta.CSV
	log.Printf("AEAT EstadoEnvio: %s CSV: %s", estado, csv)

	if estado == "Correcto" {
		if s.hashStorage != nil {
			if err := s.hashStorage.SaveLastRecord(lastRecord); err != nil {
				return &AltaOutput{
					Success: false,
					Error:   "hash_save_error",
				}, nil
			}
		}
		return &AltaOutput{
			Success: true,
			CSV:     csv,
			Estado:  "Correcto",
		}, nil
	}

	errMsg := estado
	if len(resp.Body.Respuesta.RespuestaLineas) > 0 {
		l := resp.Body.Respuesta.RespuestaLineas[0]
		errMsg = fmt.Sprintf("%s [%s] %s", estado, l.CodigoError, l.DescripcionError)
	}
	log.Printf("AEAT error: %s", errMsg)
	return &AltaOutput{
		Success: false,
		Error:   "aeat_error: " + errMsg,
	}, nil
}

func destNombre(d *Destinatario) string {
	if d == nil {
		return ""
	}
	return d.Nombre
}

func destNIF(d *Destinatario) string {
	if d == nil {
		return ""
	}
	return d.NIF
}

func toIVAData(list []IVARegularizacion) []verifactu.IVARegularizacionData {
	out := make([]verifactu.IVARegularizacionData, len(list))
	for i, v := range list {
		out[i] = verifactu.IVARegularizacionData{
			Base:         v.Base,
			Cuota:        v.Cuota,
			Tipo:         v.Tipo,
			ClaveRegimen: v.ClaveRegimen,
			Calificacion: v.Calificacion,
		}
	}
	return out
}

type AnulacionInput struct {
	InvoiceInput
	EmisorNombre string
}

type AnulacionOutput struct {
	Success bool   `json:"success"`
	CSV     string `json:"csv,omitempty"`
	Estado  string `json:"estado,omitempty"`
	Error   string `json:"error,omitempty"`
}

func (s *FacturaService) ProcessAnulacion(input AnulacionInput) (*AnulacionOutput, error) {
	if input.Factura.EmisorNIF == "" && s.verifactu != nil {
		nif, nombre := s.verifactu.CertSubject()
		input.Factura.EmisorNIF = nif
		if input.EmisorNombre == "" {
			input.EmisorNombre = nombre
		}
	}
	if input.Factura.EmisorNIF == "" {
		return &AnulacionOutput{
			Success: false,
			Error:   "emisor_nif_required",
		}, nil
	}
	if input.Factura.NumSerie == "" {
		return &AnulacionOutput{
			Success: false,
			Error:   "num_serie_required",
		}, nil
	}
	if input.Factura.FechaExpedicion == "" {
		return &AnulacionOutput{
			Success: false,
			Error:   "fecha_expedicion_required",
		}, nil
	}

	return &AnulacionOutput{
		Success: true,
		Estado:  "Anulada",
	}, nil
}
