package conversion

import (
	"os"
	"testing"

	"github.com/stretchr/testify/require"
)

const testDialect = `<?xml version="1.0"?>
<mavlink>
  <version>0</version>
  <dialect>0</dialect>
  <enums>
    <enum name="A_TYPE">
      <description>Detected Anomaly Types.</description>
      <entry value="0" name="A">
        <description>A.</description>
      </entry>
      <entry value="1" name="B">
        <description>B.</description>
      </entry>
      <entry value="2" name="C">
        <description>C.</description>
      </entry>
      <entry value="3" name="D">
        <description>D.</description>
      </entry>
      <entry value="4" name="E">
        <description>E</description>
      </entry>
      <entry value="1" name="BIT0" />
      <entry value="2**4" name="BIT4" />
      <entry value="0b000100000000" name="BIT8" />
      <entry value="0x10000" name="BIT16" />
      <entry value="0b1000000000000000000000000000000000000000000000000000000000000" name="BIT60" />
      <entry value="2305843009213693952" name="BIT61" />
      <entry value="2**62" name="BIT62" />
      <entry value="0x8000000000000000" name="BIT63" />
    </enum>
  </enums>
  <messages>
    <message id="43000" name="A_MESSAGE">
      <description>Detected anomaly info measured by onboard sensors and actuators. </description>
      <field type="uint8_t" name="test_uint8" enum="A_TYPE">a test uint8</field>
	  <field type="char[16]" name="Test_string">a test string</field>
	  <field type="uint32_t[4]" name="test_array">a test array</field>
	  <extensions/>
      <field type="uint8_t" name="mission_type" enum="MAV_MISSION_TYPE">a test extension</field>
    </message>
  </messages>
</mavlink>
`

var testMessageGo = `//autogenerated:yes
//nolint:revive,misspell,govet,lll
package testdialect
// Detected anomaly info measured by onboard sensors and actuators.
type MessageAMessage struct {
	// a test uint8
	TestUint8 A_TYPE ` + "`" + `mavenum:"uint8"` + "`" + `
	// a test string
	TestString string ` + "`" + `mavlen:"16" mavname:"Test_string"` + "`" + `
	// a test array
	TestArray [4]uint32
	// a test extension
	MissionType MAV_MISSION_TYPE ` + "`" + `mavenum:"uint8" mavext:"true"` + "`" + `
}

// GetID implements the message.Message interface.
func (*MessageAMessage) GetID() uint32 {
	return 43000
}
`

var testEnumGo = `//autogenerated:yes
//nolint:revive,misspell,govet,lll,dupl,gocritic
package testdialect

import (
	"strconv"
	"fmt"
)
// Detected Anomaly Types.
type A_TYPE uint64

const (
	// A.
	A A_TYPE = 0
	// B.
	B A_TYPE = 1
	// C.
	C A_TYPE = 2
	// D.
	D A_TYPE = 3
	// E
	E A_TYPE = 4
	BIT0 A_TYPE = 1
	BIT4 A_TYPE = 16
	BIT8 A_TYPE = 256
	BIT16 A_TYPE = 65536
	BIT60 A_TYPE = 1152921504606846976
	BIT61 A_TYPE = 2305843009213693952
	BIT62 A_TYPE = 4611686018427387904
	BIT63 A_TYPE = 9223372036854775808
)

var value_to_label_A_TYPE = map[A_TYPE]string{
	A: "A",
	B: "B",
	C: "C",
	D: "D",
	E: "E",
	BIT0: "BIT0",
	BIT4: "BIT4",
	BIT8: "BIT8",
	BIT16: "BIT16",
	BIT60: "BIT60",
	BIT61: "BIT61",
	BIT62: "BIT62",
	BIT63: "BIT63",
}

var label_to_value_A_TYPE = map[string]A_TYPE{
	"A": A,
	"B": B,
	"C": C,
	"D": D,
	"E": E,
	"BIT0": BIT0,
	"BIT4": BIT4,
	"BIT8": BIT8,
	"BIT16": BIT16,
	"BIT60": BIT60,
	"BIT61": BIT61,
	"BIT62": BIT62,
	"BIT63": BIT63,
}

// MarshalText implements the encoding.TextMarshaler interface.
func (e A_TYPE) MarshalText() ([]byte, error) {
	if name, ok := value_to_label_A_TYPE[e]; ok {
		return []byte(name), nil
	}
	return []byte(strconv.Itoa(int(e))), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (e *A_TYPE) UnmarshalText(text []byte) error {
	if value, ok := label_to_value_A_TYPE[string(text)]; ok {
	   *e = value
	} else if value, err := strconv.Atoi(string(text)); err == nil {
	   *e = A_TYPE(value)
	} else {
		return fmt.Errorf("invalid label '%s'", text)
	}
	return nil
}

// String implements the fmt.Stringer interface.
func (e A_TYPE) String() string {
	val, _ := e.MarshalText()
	return string(val)
}
`

func TestConversion(t *testing.T) {
	dir, err := os.MkdirTemp("", "gomavlib")
	require.NoError(t, err)
	defer os.RemoveAll(dir)

	os.Chdir(dir)

	err = os.WriteFile("testdialect.xml", []byte(testDialect), 0o644)
	require.NoError(t, err)

	err = Convert("testdialect.xml", true)
	require.NoError(t, err)

	buf, err := os.ReadFile("testdialect/message_a_message.go")
	require.NoError(t, err)
	require.Equal(t, testMessageGo, string(buf))

	buf, err = os.ReadFile("testdialect/enum_a_type.go")
	require.NoError(t, err)
	require.Equal(t, testEnumGo, string(buf))
}
