using Elwig.Helpers;

namespace Tests.UnitTests.HelperTests {
    [TestFixture]
    public class UtilsTest {

        private static readonly double[,] Gradation = new double[,] {
            { 14.0,  68.0 },
            { 15.0,  73.0 },
            { 17.1,  84.0 },
            { 19.0,  94.0 },
            { 21.0, 105.0 },
            { 25.0, 127.0 },
            { 27.1, 139.0 },
            { 30.0, 156.0 },
        };

        [Test]
        public void Test_KmwToOe() {
            Assert.Multiple(() => {
                for (int i = 0; i < Gradation.GetLength(0); i++) {
                    Assert.That(Utils.KmwToOe(Gradation[i, 0]), Is.EqualTo(Gradation[i, 1]));
                }
            });
        }

        [Test]
        public void Test_OeToKmw() {
            Assert.Multiple(() => {
                for (int i = 0; i < Gradation.GetLength(0); i++) {
                    Assert.That(Utils.OeToKmw(Gradation[i, 1]), Is.EqualTo(Gradation[i, 0]));
                }
            });
        }

        [Test]
        public void Test_DecFromDb() {
            Assert.Multiple(() => {
                Assert.That(Utils.DecFromDb(10670, 3), Is.EqualTo(10.67M));
                Assert.That(Utils.DecFromDb(-1009999, 4), Is.EqualTo(-100.9999M));
                Assert.That(Utils.DecFromDb(1, 2), Is.EqualTo(0.01M));
            });
        }

        [Test]
        public void Test_DecToDb() {
            Assert.Multiple(() => {
                Assert.That(Utils.DecToDb(219.48M, 2), Is.EqualTo(21948));
                Assert.That(Utils.DecToDb(-1.2345M, 4), Is.EqualTo(-12345));
                Assert.That(Utils.DecToDb(99190, 0), Is.EqualTo(99190));
                Assert.That(Utils.DecToDb(817.9099M, 3), Is.EqualTo(817910));
                Assert.That(Utils.DecToDb(-5618.944M, 2), Is.EqualTo(-561894));
            });
        }

        [Test]
        public void Test_Modulo() {
            Assert.Multiple(() => {
                Assert.That(Utils.Modulo("1", 2), Is.EqualTo(1));
                Assert.That(Utils.Modulo("12", 11), Is.EqualTo(1));
                Assert.That(Utils.Modulo("65", 16), Is.EqualTo(1));
                Assert.That(Utils.Modulo("91746381048364", 10), Is.EqualTo(4));
                Assert.That(Utils.Modulo("210501700012345678131468", 97), Is.EqualTo(1));
                Assert.Throws<ArgumentException>(() => Utils.Modulo("", 4));
                Assert.Throws<ArgumentException>(() => Utils.Modulo("1ab", 5));
                Assert.Throws<ArgumentException>(() => Utils.Modulo("123", 1));
                Assert.Throws<ArgumentException>(() => Utils.Modulo("456", 0));
                Assert.Throws<ArgumentException>(() => Utils.Modulo("789", -1));
            });
        }

        [Test]
        public void Test_SplitAddress() {
            Assert.Multiple(() => {
                Assert.That(Utils.SplitAddress("Winzerstraße 1"), Is.EqualTo(("Winzerstraße", "1")));
                Assert.That(Utils.SplitAddress("Auf dem Feld 12"), Is.EqualTo(("Auf dem Feld", "12")));
                Assert.That(Utils.SplitAddress("Winzerstraße 5a"), Is.EqualTo(("Winzerstraße", "5a")));
                Assert.That(Utils.SplitAddress("Winzerstraße 1-3/2"), Is.EqualTo(("Winzerstraße", "1-3/2")));
                Assert.That(Utils.SplitAddress("Winzerstraße 3/4/5"), Is.EqualTo(("Winzerstraße", "3/4/5")));
                Assert.That(Utils.SplitAddress("Winzerstraße 7/2/4/77"), Is.EqualTo(("Winzerstraße", "7/2/4/77")));
                Assert.That(Utils.SplitAddress("Winzerstraße 95b"), Is.EqualTo(("Winzerstraße", "95b")));
                Assert.That(Utils.SplitAddress("Winzerstraße 1, TOP 3"), Is.EqualTo(("Winzerstraße", "1, TOP 3")));
            });
        }

        [Test]
        public void Test_SplitName() {
            Assert.Multiple(() => {
                Assert.That(Utils.SplitName("Max Bauer", "Bauer"), Is.EqualTo(("Bauer", "Max")));
                Assert.That(Utils.SplitName("Bauer Max", "Bauer"), Is.EqualTo(("Bauer", "Max")));
                Assert.That(Utils.SplitName("Max und Moritz Bauer", "Bauer"), Is.EqualTo(("Bauer", "Max und Moritz")));
                Assert.That(Utils.SplitName("Bauer Max und Moritz", "Bauer"), Is.EqualTo(("Bauer", "Max und Moritz")));
                Assert.That(Utils.SplitName("Bauer GesbR", "Bauer"), Is.EqualTo(("Bauer", "GesbR")));
                Assert.That(Utils.SplitName("Max und Moritz Bauer GesbR", "Bauer"), Is.EqualTo(("Bauer", "Max und Moritz GesbR")));
                Assert.That(Utils.SplitName("Bauer Max und Moritz GesbR", "Bauer"), Is.EqualTo(("Bauer", "Max und Moritz GesbR")));
                Assert.That(Utils.SplitName("Weingut Bauer", "Bauer"), Is.EqualTo(("Bauer", "Weingut")));
                Assert.That(Utils.SplitName("Bauer Weingut", "Bauer"), Is.EqualTo(("Bauer", "Weingut")));
                Assert.That(Utils.SplitName("Max und Moritz Bauer und Mustermann", "Bauer"), Is.EqualTo(("Bauer und Mustermann", "Max und Moritz")));
                Assert.That(Utils.SplitName("Bauer und Mustermann Max und Moritz", "Bauer"), Is.EqualTo(("Bauer und Mustermann", "Max und Moritz")));
                Assert.That(Utils.SplitName("ABC GesbR", "Bauer"), Is.EqualTo(((string, string?))("ABC GesbR", null)));
            });
        }

        [Test]
        public void Test_CalcCrc16Modbus() {
            Assert.Multiple(() => {
                Assert.That(Utils.CalcCrc16Modbus(""), Is.EqualTo(0xFFFF));
                Assert.That(Utils.CalcCrc16Modbus("abcd"), Is.EqualTo(0x1D97));
                Assert.That(Utils.CalcCrc16Modbus("ABCD"), Is.EqualTo(0x0F85));
                // Matzen (SysTec IT3000A)
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:03   01       0       0       0kg     1"), Is.EqualTo(43166));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:04   01       0       0       0kg     1"), Is.EqualTo(21615));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:05   01       0       0       0kg     1"), Is.EqualTo(40446));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:06   01       0       0       0kg     1"), Is.EqualTo(34638));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:07   01       0       0       0kg     1"), Is.EqualTo(20191));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:08   01       0       0       0kg     1"), Is.EqualTo(16047));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:09   01       0       0       0kg     1"), Is.EqualTo(63294));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:10   01       0       0       0kg     1"), Is.EqualTo(7718));
                Assert.That(Utils.CalcCrc16Modbus("000011.08.2319:12   01       0       0       0kg     1"), Is.EqualTo(52487));
                // Wolkersdorf, Waage 1 (SysTec IT6000E)
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:50   51       0       0       0kg     A"), Is.EqualTo(10187));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:50   61       0       0       0kg     A"), Is.EqualTo(20683));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:50   71       0       0       0kg     A"), Is.EqualTo(48586));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:50   81       0       0       0kg     A"), Is.EqualTo(22217));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:50   91       0       0       0kg     A"), Is.EqualTo(48072));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51  101       0       0       0kg     A"), Is.EqualTo(30119));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51  111       0       0       0kg     A"), Is.EqualTo(39078));
                // Wolkersdorf, Waage 2 (SysTec IT6000E)
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51   41       0       0       0kg     B"), Is.EqualTo(539));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51   51       0       0       0kg     B"), Is.EqualTo(61210));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51   61       0       0       0kg     B"), Is.EqualTo(38938));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51   71       0       0       0kg     B"), Is.EqualTo(29979));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51   81       0       0       0kg     B"), Is.EqualTo(40472));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51   91       0       0       0kg     B"), Is.EqualTo(29465));
                Assert.That(Utils.CalcCrc16Modbus("000004.09.2315:51  101       0       0       0kg     B"), Is.EqualTo(29927));
                // Gr.Inzersdorf (L246/IT3)
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   11       0       0       0kg   001"), Is.EqualTo(27556));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   21       0       0       0kg   001"), Is.EqualTo(7332));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   31       0       0       0kg   001"), Is.EqualTo(61861));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   41       0       0       0kg   001"), Is.EqualTo(62116));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   51       0       0       0kg   001"), Is.EqualTo(8101));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   61       0       0       0kg   001"), Is.EqualTo(26789));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:49   71      50       0      50kg   001"), Is.EqualTo(16188));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:50   81      35       0      35kg   001"), Is.EqualTo(12015));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:50   91      40       0      40kg   001"), Is.EqualTo(60047));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:50  101      40       0      40kg   001"), Is.EqualTo(60785));
                Assert.That(Utils.CalcCrc16Modbus("000019.02.2410:50  111      45       0      45kg   001"), Is.EqualTo(35918));
            });
        }
    }
}
