
import {describe, expect, test} from 'vitest'
import Protocol, {MP3, PartySource, Source, Zone} from "../src/Protocol";

describe.concurrent('Query', () => {
    test('Command.get_status_all_zones()', async () => {
        expect(Protocol.get_status_all_zones().get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x05,0x00,0x07]));
    });

    test('Command.get_status_all()', async () => {
        expect(Protocol.get_status_all().get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x0C,0x00,0x0E]));
    });

    test('Command.get_id()', async () => {
        expect(Protocol.get_id().get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x08,0x00,0x0A]));
    });
});

describe.concurrent('All Power', () => {
    test.each([
        [true, [0x02,0x00,0x00,0x04,0x55,0x5B]],
        [false,[0x02,0x00,0x00,0x04,0x56,0x5C]],
    ])('Command.set_all_power(%j) -> %o', (power, expected) => {
        expect(Protocol.set_all_power(power).get_command()).toEqual(Buffer.from(expected));
    });
});

describe.concurrent('Set Names', () => {
    test('Command.set_zone_name(1, "Zone 1")', async () => {
        expect(Protocol.set_zone_name(1, "Zone 1").get_command()).toEqual(Buffer.from([0x02,0x00,0x01,0x06,0x00,0x5A,0x6F,0x6E,0x65,0x20,0x31,0x00,0x00,0x00,0x00,0x00,0xF6]));
    });

    // FIXME: I'm unsure as of yet if data[0] should be 1-18 (per the docs) or the source hex
    test('Command.set_zone_source_name(1, "Zone 1")', async () => {
        expect(Protocol.set_zone_source_name(1, Source._01, "DVD").get_command()).toEqual(Buffer.from([0x02,0x00,0x01,0x07,0x10,0x44,0x56,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8]));
    });
});

describe.concurrent('Files', () => {
    test.each([
        [1, [0x02,0x00,0x00,0x0A,0x01,0x0D]],
        [2, [0x02,0x00,0x00,0x0A,0x02,0x0E]],
        [3, [0x02,0x00,0x00,0x0A,0x03,0x0F]],
        [4, [0x02,0x00,0x00,0x0A,0x04,0x10]],
    ])('Command.recall_file(%i) -> %o', (file, expected) => {
        expect(Protocol.recall_file(file).get_command()).toEqual(Buffer.from(expected));
    })

    test.each([
        [1, [0x02,0x00,0x00,0x0B,0x01,0x0E]],
        [2, [0x02,0x00,0x00,0x0B,0x02,0x0F]],
        [3, [0x02,0x00,0x00,0x0B,0x03,0x10]],
        [4, [0x02,0x00,0x00,0x0B,0x04,0x11]],
    ])('Command.save_file(%i) -> %o', (file, expected) => {
        expect(Protocol.save_file(file).get_command()).toEqual(Buffer.from(expected));
    });
});


describe.concurrent('MP3', () => {
    test('Command.mp3(MP3.Back)', async () => {
        expect(Protocol.mp3(MP3.Back).get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x04,0x0C,0x12]));
    });

    test('Command.mp3(MP3.FF)', async () => {
        expect(Protocol.mp3(MP3.FF).get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x04,0x0A,0x10]));
    });

    test('Command.mp3(MP3.Play)', async () => {
        expect(Protocol.mp3(MP3.Play).get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x04,0x0B,0x11]));
    });

    test('Command.mp3(MP3.Stop)', async () => {
        expect(Protocol.mp3(MP3.Stop).get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x04,0x0D,0x13]));
    });

    test('Command.mp3(MP3.Repeat_Off)', async () => {
        expect(Protocol.mp3(MP3.Repeat_Off).get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x01,0x00,0x03]));
    });

    test('Command.mp3(MP3.Repeat_On)', async () => {
        expect(Protocol.mp3(MP3.Repeat_On).get_command()).toEqual(Buffer.from([0x02,0x00,0x00,0x01,0xFF,0x102]));
    });
});

describe.concurrent('DND', () => {
    test.concurrent.each([
        [ 1, true,	[0x02,0x00,0x01,0x04,0x59,0x60]],
        [ 2, true,	[0x02,0x00,0x02,0x04,0x59,0x61]],
        [ 3, true,	[0x02,0x00,0x03,0x04,0x59,0x62]],
        [ 4, true,	[0x02,0x00,0x04,0x04,0x59,0x63]],
        [ 5, true,	[0x02,0x00,0x05,0x04,0x59,0x64]],
        [ 6, true,	[0x02,0x00,0x06,0x04,0x59,0x65]],
        [ 7, true,	[0x02,0x00,0x07,0x04,0x59,0x66]],
        [ 8, true,	[0x02,0x00,0x08,0x04,0x59,0x67]],
        [ 9, true,	[0x02,0x00,0x09,0x04,0x59,0x68]],
        [10, true,	[0x02,0x00,0x0A,0x04,0x59,0x69]],
        [11, true,	[0x02,0x00,0x0B,0x04,0x59,0x6A]],
        [12, true,	[0x02,0x00,0x0C,0x04,0x59,0x6B]],
        [ 1, false,	[0x02,0x00,0x01,0x04,0x5A,0x61]],
        [ 2, false,	[0x02,0x00,0x02,0x04,0x5A,0x62]],
        [ 3, false,	[0x02,0x00,0x03,0x04,0x5A,0x63]],
        [ 4, false,	[0x02,0x00,0x04,0x04,0x5A,0x64]],
        [ 5, false,	[0x02,0x00,0x05,0x04,0x5A,0x65]],
        [ 6, false,	[0x02,0x00,0x06,0x04,0x5A,0x66]],
        [ 7, false,	[0x02,0x00,0x07,0x04,0x5A,0x67]],
        [ 8, false,	[0x02,0x00,0x08,0x04,0x5A,0x68]],
        [ 9, false,	[0x02,0x00,0x09,0x04,0x5A,0x69]],
        [10, false,	[0x02,0x00,0x0A,0x04,0x5A,0x6A]],
        [11, false,	[0x02,0x00,0x0B,0x04,0x5A,0x6B]],
        [12, false,	[0x02,0x00,0x0C,0x04,0x5A,0x6C]],
    ])('Command.set_dnd(%i, %j) -> %o', (zone, on, expected) => {
        expect(Protocol.set_dnd(zone, on).get_command()).toEqual(Buffer.from(expected));
    })
});

describe.concurrent('Mute', () => {
    test.concurrent.each([
        [ 1, true,	[0x02,0x00,0x01,0x04,0x1E,0x25]],
        [ 2, true,	[0x02,0x00,0x02,0x04,0x1E,0x26]],
        [ 3, true,	[0x02,0x00,0x03,0x04,0x1E,0x27]],
        [ 4, true,	[0x02,0x00,0x04,0x04,0x1E,0x28]],
        [ 5, true,	[0x02,0x00,0x05,0x04,0x1E,0x29]],
        [ 6, true,	[0x02,0x00,0x06,0x04,0x1E,0x2A]],
        [ 7, true,	[0x02,0x00,0x07,0x04,0x1E,0x2B]],
        [ 8, true,	[0x02,0x00,0x08,0x04,0x1E,0x2C]],
        [ 9, true,	[0x02,0x00,0x09,0x04,0x1E,0x2D]],
        [10, true,	[0x02,0x00,0x0A,0x04,0x1E,0x2E]],
        [11, true,	[0x02,0x00,0x0B,0x04,0x1E,0x2F]],
        [12, true,	[0x02,0x00,0x0C,0x04,0x1E,0x30]],
        [ 1, false,	[0x02,0x00,0x01,0x04,0x1F,0x26]],
        [ 2, false,	[0x02,0x00,0x02,0x04,0x1F,0x27]],
        [ 3, false,	[0x02,0x00,0x03,0x04,0x1F,0x28]],
        [ 4, false,	[0x02,0x00,0x04,0x04,0x1F,0x29]],
        [ 5, false,	[0x02,0x00,0x05,0x04,0x1F,0x2A]],
        [ 6, false,	[0x02,0x00,0x06,0x04,0x1F,0x2B]],
        [ 7, false,	[0x02,0x00,0x07,0x04,0x1F,0x2C]],
        [ 8, false,	[0x02,0x00,0x08,0x04,0x1F,0x2D]],
        [ 9, false,	[0x02,0x00,0x09,0x04,0x1F,0x2E]],
        [10, false,	[0x02,0x00,0x0A,0x04,0x1F,0x2F]],
        [11, false,	[0x02,0x00,0x0B,0x04,0x1F,0x30]],
        [12, false,	[0x02,0x00,0x0C,0x04,0x1F,0x31]],
    ])('Command.set_mute(%i, %j) -> %o', (zone, on, expected) => {
        expect(Protocol.set_mute(zone, on).get_command()).toEqual(Buffer.from(expected));
    })
});

describe.concurrent('Zone Power', () => {
    test.concurrent.each([
        [ 0, true,	[0x02,0x00,0x00,0x04,0x57,0x5D]],
        [ 1, true,	[0x02,0x00,0x01,0x04,0x57,0x5E]],
        [ 2, true,	[0x02,0x00,0x02,0x04,0x57,0x5F]],
        [ 3, true,	[0x02,0x00,0x03,0x04,0x57,0x60]],
        [ 4, true,	[0x02,0x00,0x04,0x04,0x57,0x61]],
        [ 5, true,	[0x02,0x00,0x05,0x04,0x57,0x62]],
        [ 6, true,	[0x02,0x00,0x06,0x04,0x57,0x63]],
        [ 7, true,	[0x02,0x00,0x07,0x04,0x57,0x64]],
        [ 8, true,	[0x02,0x00,0x08,0x04,0x57,0x65]],
        [ 9, true,	[0x02,0x00,0x09,0x04,0x57,0x66]],
        [10, true,	[0x02,0x00,0x0A,0x04,0x57,0x67]],
        [11, true,	[0x02,0x00,0x0B,0x04,0x57,0x68]],
        [12, true,	[0x02,0x00,0x0C,0x04,0x57,0x69]],
        [ 0, false,	[0x02,0x00,0x00,0x04,0x58,0x5E]],
        [ 1, false,	[0x02,0x00,0x01,0x04,0x58,0x5F]],
        [ 2, false,	[0x02,0x00,0x02,0x04,0x58,0x60]],
        [ 3, false,	[0x02,0x00,0x03,0x04,0x58,0x61]],
        [ 4, false,	[0x02,0x00,0x04,0x04,0x58,0x62]],
        [ 5, false,	[0x02,0x00,0x05,0x04,0x58,0x63]],
        [ 6, false,	[0x02,0x00,0x06,0x04,0x58,0x64]],
        [ 7, false,	[0x02,0x00,0x07,0x04,0x58,0x65]],
        [ 8, false,	[0x02,0x00,0x08,0x04,0x58,0x66]],
        [ 9, false,	[0x02,0x00,0x09,0x04,0x58,0x67]],
        [10, false,	[0x02,0x00,0x0A,0x04,0x58,0x68]],
        [11, false,	[0x02,0x00,0x0B,0x04,0x58,0x69]],
        [12, false,	[0x02,0x00,0x0C,0x04,0x58,0x6A]],
    ])('Command.set_zone_power(%i, %j) -> %o', (zone, on, expected) => {
        expect(Protocol.set_zone_power(zone, on).get_command()).toEqual(Buffer.from(expected));
    })
});

describe.concurrent('Party Mode (docs were wrong)', () => {
    test.concurrent.each([
        [PartySource._01, [0x02,0x00,0x00,0x04,0x36,0x3C]],
        [PartySource._02, [0x02,0x00,0x00,0x04,0x37,0x3D]],
        [PartySource._03, [0x02,0x00,0x00,0x04,0x38,0x3E]],
        [PartySource._04, [0x02,0x00,0x00,0x04,0x39,0x3F]],
        [PartySource._05, [0x02,0x00,0x00,0x04,0x3A,0x40]],
        [PartySource._06, [0x02,0x00,0x00,0x04,0x3B,0x41]],
        [PartySource._07, [0x02,0x00,0x00,0x04,0x3C,0x42]],
        [PartySource._08, [0x02,0x00,0x00,0x04,0x3D,0x43]],
        [PartySource._09, [0x02,0x00,0x00,0x04,0x3E,0x44]],
        [PartySource._10, [0x02,0x00,0x00,0x04,0x3F,0x45]],
        [PartySource._11, [0x02,0x00,0x00,0x04,0x40,0x46]],
        [PartySource._12, [0x02,0x00,0x00,0x04,0x41,0x47]],
        [PartySource._13, [0x02,0x00,0x00,0x04,0x69,0x6F]],
        [PartySource._14, [0x02,0x00,0x00,0x04,0x6A,0x70]],
        [PartySource._15, [0x02,0x00,0x00,0x04,0x6B,0x71]],
        [PartySource._16, [0x02,0x00,0x00,0x04,0x6C,0x72]],
        [PartySource._17, [0x02,0x00,0x00,0x04,0x6D,0x73]],
        [PartySource._18, [0x02,0x00,0x00,0x04,0x6E,0x74]]
    ])('Command.set_party_mode(%i) -> %o', (party_input, expected) => {
        expect(Protocol.set_party_mode(party_input).get_command()).toEqual(Buffer.from(expected));
    })
});



describe.concurrent('Zone Settings', async () => {
    test.concurrent.each([
        [Zone._01, -25, [0x02,0x00,0x01,0x16,0xEE,0x07], 'below minimum'],
        [Zone._01, -18, [0x02,0x00,0x01,0x16,0xEE,0x07], 'minimum'],
        [Zone._01,  -5, [0x02,0x00,0x01,0x16,0xFB,0x14], 'left'],
        [Zone._01,   0, [0x02,0x00,0x01,0x16,0x00,0x19], 'center'],
        [Zone._01,   5, [0x02,0x00,0x01,0x16,0x05,0x1E], 'right'],
        [Zone._01,  18, [0x02,0x00,0x01,0x16,0x12,0x2B], 'maximum'],
        [Zone._01,  25, [0x02,0x00,0x01,0x16,0x12,0x2B], 'above maximum'],
    ])('Command.set_balance(%i, %i) -> %o - %s', async (zone, balance, expected) => {
        expect(Protocol.set_balance(zone, balance).get_command()).toEqual(Buffer.from(expected));
    });

    test.concurrent.each([
        [Zone._01, -15, [0x02,0x00,0x01,0x17,0xF6,0x10], 'below minimum'],
        [Zone._01, -10, [0x02,0x00,0x01,0x17,0xF6,0x10], 'minimum'],
        [Zone._01,  -5, [0x02,0x00,0x01,0x17,0xFB,0x15], 'low'],
        [Zone._01,   0, [0x02,0x00,0x01,0x17,0x00,0x1A], 'none'],
        [Zone._01,   5, [0x02,0x00,0x01,0x17,0x05,0x1F], 'high'],
        [Zone._01,  10, [0x02,0x00,0x01,0x17,0x0A,0x24], 'maximum'],
        [Zone._01,  15, [0x02,0x00,0x01,0x17,0x0A,0x24], 'above maximum'],
    ])('Command.set_treble(%i, %i) -> %o - %s', async (zone, treble, expected) => {
        expect(Protocol.set_treble(zone, treble).get_command()).toEqual(Buffer.from(expected));
    });

    test.concurrent.each([
        [Zone._01, -15, [0x02,0x00,0x01,0x18,0xF6,0x11], 'below minimum'],
        [Zone._01, -10, [0x02,0x00,0x01,0x18,0xF6,0x11], 'minimum'],
        [Zone._01,  -5, [0x02,0x00,0x01,0x18,0xFB,0x16], 'low'],
        [Zone._01,   0, [0x02,0x00,0x01,0x18,0x00,0x1B], 'none'],
        [Zone._01,   5, [0x02,0x00,0x01,0x18,0x05,0x20], 'high'],
        [Zone._01,  10, [0x02,0x00,0x01,0x18,0x0A,0x25], 'maximum'],
        [Zone._01,  15, [0x02,0x00,0x01,0x18,0x0A,0x25], 'above maximum'],
    ])('Command.set_bass(%i, %i) -> %o - %s', async (zone, treble, expected) => {
        expect(Protocol.set_bass(zone, treble).get_command()).toEqual(Buffer.from(expected));
    });
});