package facturacionOperaciones

import (
	"api-soap-facturacion/internal/config"
	"api-soap-facturacion/internal/logger"
	mfo "api-soap-facturacion/internal/models/facturacionOperaciones"
	"api-soap-facturacion/pkg/soap"
	"bytes"
	"context"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
	"time"
)

// Constantes de configuración
const (
	DefaultTimeout = 30 * time.Second
	ContentType    = "text/xml;charset=UTF-8"
	SoapAction     = "https://siat.impuestos.gob.bo/registroPuntoVenta"
	SiatEndpoint   = "https://pilotosiatservicios.impuestos.gob.bo/v2/FacturacionOperaciones"
)

// NewClient crea una nueva instancia del cliente SOAP
func NewClient(options *ClientOptions, config config.APIConfig, log logger.Logger) *Client {

	// Configurar cliente SOAP
	factOperaciones := soap.ClientOptions{
		Endpoint: config.Endpoint,
		Username: config.Username,
		Password: config.Password,
		Timeout:  config.Timeout * time.Second,
		Headers: map[string]string{
			"User-Agent": "soap-api-client/1.0",
		},
	}

	client := &Client{
		endpointURL: SiatEndpoint,
		soapClient:  soap.NewClient(factOperaciones),
		logger:      log,
	}

	if options != nil {
		if options.EndpointURL != "" {
			client.endpointURL = options.EndpointURL
		}

		if options.HTTPClient != nil {
			client.httpClient = options.HTTPClient
		}
	}

	if client.httpClient == nil {
		timeout := DefaultTimeout
		if options != nil && options.Timeout > 0 {
			timeout = options.Timeout
		}

		client.httpClient = &http.Client{
			Timeout: timeout,
		}
	}

	return client
}

// envía una solicitud para registrar un punto de venta en SIAT
func (c *Client) RegistrarPuntoVenta(ctx context.Context, solicitud mfo.SolicitudRegistroPuntoVenta) (*mfo.RespuestaRegistroPuntoVenta, error) {
	// Preparar la petición SOAP
	request := mfo.RegistroPuntoVentaRequest{
		SoapEnv: "http://schemas.xmlsoap.org/soap/envelope/",
		Siat:    "https://siat.impuestos.gob.bo/",
	}
	request.Body.RegistroPuntoVenta.Solicitud = solicitud

	// Convertir la petición a XML
	requestBody, err := xml.MarshalIndent(request, "", "  ")
	if err != nil {
		return nil, fmt.Errorf("error al convertir la solicitud a XML: %w", err)
	}

	// Crear la petición HTTP con el contexto
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpointURL, bytes.NewReader(requestBody))
	if err != nil {
		return nil, fmt.Errorf("error al crear la petición HTTP: %w", err)
	}

	// Configurar encabezados
	req.Header.Set("Content-Type", ContentType)
	req.Header.Set("SOAPAction", SoapAction)

	// Realizar la petición HTTP
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error al realizar la petición HTTP: %w", err)
	}
	defer resp.Body.Close()

	// Leer el cuerpo de la respuesta
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("error al leer la respuesta: %w", err)
	}

	// Verificar el código de estado HTTP
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("error en la respuesta HTTP: %s, cuerpo: %s", resp.Status, respBody)
	}

	// Parsear la respuesta
	var soapResponse mfo.RegistroPuntoVentaResponse
	if err := xml.Unmarshal(respBody, &soapResponse); err != nil {
		return nil, fmt.Errorf("error al parsear la respuesta XML: %w, cuerpo: %s", err, respBody)
	}

	return &soapResponse.Body.RegistroPuntoVentaResponse.Respuesta, nil
}
