package stanza_test

import (
	"encoding/xml"
	"errors"
	"regexp"
	"testing"

	"github.com/google/go-cmp/cmp"
	"gosrc.io/xmpp/stanza"
)

var reLeadcloseWhtsp = regexp.MustCompile(`^[\s\p{Zs}]+|[\s\p{Zs}]+$`)
var reInsideWhtsp = regexp.MustCompile(`[\s\p{Zs}]`)

// ============================================================================
// Marshaller / unmarshaller test

func checkMarshalling(t *testing.T, iq *stanza.IQ) (*stanza.IQ, error) {
	// Marshall
	data, err := xml.Marshal(iq)
	if err != nil {
		t.Errorf("cannot marshal iq: %s\n%#v", err, iq)
		return nil, err
	}

	// Unmarshall
	var parsedIQ stanza.IQ
	err = xml.Unmarshal(data, &parsedIQ)
	if err != nil {
		t.Errorf("Unmarshal returned error: %s\n%s", err, data)
	}
	return &parsedIQ, err
}

// ============================================================================
// XML structs comparison

// Compare iq structure but ignore empty namespace as they are set properly on
// marshal / unmarshal. There is no need to manage them on the manually
// crafted structure.
func xmlEqual(x, y interface{}) bool {
	return cmp.Equal(x, y, xmlOpts())
}

// xmlDiff compares xml structures ignoring namespace preferences
func xmlDiff(x, y interface{}) string {
	return cmp.Diff(x, y, xmlOpts())
}

func xmlOpts() cmp.Options {
	alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true })
	opts := cmp.Options{
		cmp.FilterValues(func(x, y interface{}) bool {
			xx, xok := x.(xml.Name)
			yy, yok := y.(xml.Name)
			if xok && yok {
				zero := xml.Name{}
				if xx == zero || yy == zero {
					return true
				}
				if xx.Space == "" || yy.Space == "" {
					return true
				}
			}
			return false
		}, alwaysEqual),
	}
	return opts
}

func delSpaces(s string) string {
	return reInsideWhtsp.ReplaceAllString(reLeadcloseWhtsp.ReplaceAllString(s, ""), "")
}

func compareMarshal(expected, data string) error {
	if delSpaces(expected) != delSpaces(data) {
		return errors.New("failed to verify unmarshal->marshal. Expected :" + expected + "\ngot: " + data)
	}
	return nil
}