const { expect } = require('chai')

const {
    compararVersoes,
    ehVersaoDeProducao,
    obterListaDeVersoesParaApresentacao,
    ordenarListaImagensETags,
    ordenarTagsDaMaisRecenteParaMaisAntiga,
    selecionarUltimaVersao,
    temPlataforma
} = require('../ordenacaoVersoes')

function tags(...nomes) {
    return nomes.map(nome => ({ name: nome }))
}

describe('ordenacaoVersoes', function () {
    describe('compararVersoes', function () {
        it('compara componente por componente, nao alfabeticamente', function () {
            // O bug que aparecia na tela do atualizador: 1.10.0 vinha entre
            // 1.1.0 e 1.2.0 porque a lista nao era ordenada por numero.
            expect(compararVersoes('1.10.0', '1.9.0')).to.equal(1)
            expect(compararVersoes('1.9.0', '1.10.0')).to.equal(-1)
            expect(compararVersoes('2.0.0', '1.99.99')).to.equal(1)
        })

        it('trata componente ausente como zero', function () {
            expect(compararVersoes('1.80', '1.80.0')).to.equal(0)
            expect(compararVersoes('1.80', '1.7.0')).to.equal(1)
        })

        it('ignora o sufixo de plataforma na precedencia', function () {
            expect(compararVersoes('5.4.9-linux', '5.4.9')).to.equal(0)
            expect(compararVersoes('1.4.2-windows-2016', '1.4.2')).to.equal(0)
            expect(compararVersoes('5.4.12-linux', '5.4.9-windows')).to.equal(1)
        })

        it('coloca pre-lancamento abaixo da versao final', function () {
            expect(compararVersoes('1.6.0-rc1', '1.6.0')).to.equal(-1)
            expect(compararVersoes('0.9-beta', '0.9')).to.equal(-1)
            expect(compararVersoes('1.6.0-rc2', '1.6.0-rc1')).to.equal(1)
        })

        it('coloca branch de ficha abaixo da versao oficial mesmo comecando com numero', function () {
            // Branch de ficha comeca com o numero da ficha, que e maior que
            // qualquer numero de versao: 493081 vs 5.111.2.
            expect(compararVersoes('5.111.2', '493081_junio_SacolaAdicionarProduto_Predial')).to.equal(1)
            expect(compararVersoes('493081_junio_SacolaAdicionarProduto_Predial', '5.111.2')).to.equal(-1)
            expect(compararVersoes('5.109.0', '475218_Centaurus_ListaOferta')).to.equal(1)
            expect(compararVersoes('5.109.0', '491925_liberacao_desconto')).to.equal(1)
        })

        it('mantem a ficha mais nova acima da mais antiga entre branches', function () {
            expect(compararVersoes('493081_junio_Sacola', '492914_marcio_Menu')).to.equal(1)
            expect(compararVersoes('482572_RecuperarOrcamento_MU', '489868_fulfilment')).to.equal(-1)
        })

        it('coloca branch abaixo de qualquer versao numerica', function () {
            expect(compararVersoes('1.4.2-windows-2016', 'FNX-5220-windows')).to.equal(1)
            expect(compararVersoes('FNX-5220-windows', '1.4.2-windows-2016')).to.equal(-1)
            expect(compararVersoes('FNX-5220-windows', 'FNX-5320-windows')).to.equal(-1)
        })

        it('devolve 0 quando alguma tag e nula ou vazia', function () {
            expect(compararVersoes(null, '1.5.0-linux')).to.equal(0)
            expect(compararVersoes(null, null)).to.equal(0)
            expect(compararVersoes('', '1.5.0')).to.equal(0)
        })
    })

    describe('ordenarTagsDaMaisRecenteParaMaisAntiga', function () {
        it('ordena decrescente com a maior versao primeiro', function () {
            const ordenadas = ordenarTagsDaMaisRecenteParaMaisAntiga([
                '1.0.0', '1.1.0', '1.10.0', '1.2.0', '1.3.0', '1.9.0'
            ])

            expect(ordenadas).to.deep.equal([
                '1.10.0', '1.9.0', '1.3.0', '1.2.0', '1.1.0', '1.0.0'
            ])
        })

        it('joga as branches para o fim da lista', function () {
            const ordenadas = ordenarTagsDaMaisRecenteParaMaisAntiga([
                'FNX-5220', '1.2.0', 'master', '1.10.0'
            ])

            expect(ordenadas.slice(0, 2)).to.deep.equal(['1.10.0', '1.2.0'])
            expect(ordenadas.slice(2)).to.have.members(['FNX-5220', 'master'])
        })

        it('aceita lista vazia, nula e com itens vazios', function () {
            expect(ordenarTagsDaMaisRecenteParaMaisAntiga([])).to.deep.equal([])
            expect(ordenarTagsDaMaisRecenteParaMaisAntiga(null)).to.deep.equal([])
            expect(ordenarTagsDaMaisRecenteParaMaisAntiga(['1.2.0', null, ''])).to.deep.equal(['1.2.0'])
        })
    })

    describe('ordenarListaImagensETags', function () {
        it('ordena pelo campo name sem alterar a lista recebida', function () {
            const lista = tags('1.0.0', '1.10.0', '1.2.0')

            const ordenada = ordenarListaImagensETags(lista)

            expect(ordenada.map(e => e.name)).to.deep.equal(['1.10.0', '1.2.0', '1.0.0'])
            expect(lista.map(e => e.name)).to.deep.equal(['1.0.0', '1.10.0', '1.2.0'])
        })
    })

    describe('obterListaDeVersoesParaApresentacao', function () {
        it('devolve as versoes uma por linha, da mais recente para a mais antiga', function () {
            const apresentacao = obterListaDeVersoesParaApresentacao(
                tags('1.0.0', '1.1.0', '1.10.0', '1.2.0', '1.9.0')
            )

            expect(apresentacao).to.equal('1.10.0\n1.9.0\n1.2.0\n1.1.0\n1.0.0')
        })
    })

    describe('formatos de versao oficial que existem hoje', function () {
        it('mantem as tags com plataforma da Enterprise em ordem', function () {
            const apresentadas = obterListaDeVersoesParaApresentacao(
                tags('5.4.5-linux', '5.4.9-linux', '5.4.7-linux')
            ).split('\n')

            expect(apresentadas).to.deep.equal(['5.4.9-linux', '5.4.7-linux', '5.4.5-linux'])
        })

        it('mantem as betas da Central de Relatorios no bloco das versoes', function () {
            // Antes da 1.0.0 as betas eram o release oficial: precisam aparecer
            // no bloco das versoes, ordenadas pelo numero, e nao junto das branches.
            const apresentadas = obterListaDeVersoesParaApresentacao(
                tags('0.2.0-beta', '1.0.0', '0.4.0-beta', '1.1.0', '0.1.0-beta', '1.0.1', '0.3.0-beta')
            ).split('\n')

            expect(apresentadas).to.deep.equal([
                '1.1.0', '1.0.1', '1.0.0', '0.4.0-beta', '0.3.0-beta', '0.2.0-beta', '0.1.0-beta'
            ])
        })

        it('coloca beta e branch em faixas diferentes', function () {
            const apresentadas = obterListaDeVersoesParaApresentacao(
                tags('0.4.0-beta', 'FNX-5220', '493081_junio_Sacola')
            ).split('\n')

            expect(apresentadas[0]).to.equal('0.4.0-beta')
        })
    })

    describe('lista real do ReleaseWeb', function () {
        // Nomes de teste nao seguem padrao nenhum: ficha com numero na frente,
        // nome de pessoa, TESTE2, master, fix_..., Branch_Teste_Production. O que
        // define versao oficial e o padrao de producao (numero com ponto).
        const DA_API = [
            '493081_junio_SacolaAdicionarProduto_Predial',
            '5.109.0',
            'TESTE2',
            '5.111.2',
            'Matheus_PA_492055_PixAPrazoWhatsapp',
            '491925_liberacao_desconto',
            'master',
            '5.110.0',
            'fix_pendencia_desconto',
            '475218_Centaurus_ListaOferta',
            'Fenix_Mapeamentos',
            '5.111.1',
            'Branch_Teste_Production',
            'MATHEUS_PA_488725_migrations',
            '489868_fulfilment'
        ]

        it('coloca todas as versoes oficiais antes de qualquer nome de teste', function () {
            const apresentadas = obterListaDeVersoesParaApresentacao(tags(...DA_API)).split('\n')

            expect(apresentadas.slice(0, 4)).to.deep.equal(['5.111.2', '5.111.1', '5.110.0', '5.109.0'])

            const nomesDeTeste = apresentadas.slice(4)

            expect(nomesDeTeste).to.have.lengthOf(DA_API.length - 4)
            expect(nomesDeTeste.some(nome => ehVersaoDeProducao(nome))).to.be.false
        })

        it('nao considera versao um nome que apenas comeca com numero', function () {
            expect(ehVersaoDeProducao('493081_junio_SacolaAdicionarProduto_Predial')).to.be.false
            expect(ehVersaoDeProducao('491925_liberacao_desconto')).to.be.false
            expect(ehVersaoDeProducao('493081')).to.be.false
            expect(ehVersaoDeProducao('TESTE2')).to.be.false
            expect(ehVersaoDeProducao('Branch_Teste_Production')).to.be.false
        })
    })

    describe('lista do ReleaseWeb com branches de ficha', function () {
        it('apresenta as versoes oficiais primeiro e as branches depois', function () {
            const daApi = tags(
                '493081_junio_SacolaAdicionarProduto_Predial',
                '5.109.2',
                '492914_marcio_MenuProdutoForaOrc_Tresmacol',
                '5.111.2',
                '489868_fulfilment',
                '5.110.0',
                '475218_Centaurus_ListaOferta',
                '5.111.0'
            )

            expect(obterListaDeVersoesParaApresentacao(daApi).split('\n')).to.deep.equal([
                '5.111.2',
                '5.111.0',
                '5.110.0',
                '5.109.2',
                '493081_junio_SacolaAdicionarProduto_Predial',
                '492914_marcio_MenuProdutoForaOrc_Tresmacol',
                '489868_fulfilment',
                '475218_Centaurus_ListaOferta'
            ])
        })
    })

    describe('selecionarUltimaVersao', function () {
        it('prefere versao de producao a branch e a pre-lancamento', function () {
            expect(selecionarUltimaVersao(['FNX-5220', '1.10.0', 'master'])).to.equal('1.10.0')
            expect(selecionarUltimaVersao(['1.6.0-rc1', '1.5.0'])).to.equal('1.5.0')
        })

        it('respeita a plataforma pedida', function () {
            const tags = ['5.4.12-linux', '5.4.9-windows']

            expect(selecionarUltimaVersao(tags, 'linux')).to.equal('5.4.12-linux')
            expect(selecionarUltimaVersao(tags, 'windows')).to.equal('5.4.9-windows')
            expect(selecionarUltimaVersao(['5.4.12-linux'], 'windows')).to.be.null
        })

        it('cai para a tag mais recente quando nao ha versao de producao', function () {
            expect(selecionarUltimaVersao(['FNX-5220', 'FNX-5320'])).to.equal('FNX-5320')
            expect(selecionarUltimaVersao([])).to.be.null
        })
    })

    describe('lista real de tags da Enterprise', function () {
        it('apresenta as versoes em ordem decrescente', function () {
            const listaReal = require('../enterprise/listaImagensETagsTeste.json')

            const apresentadas = obterListaDeVersoesParaApresentacao(listaReal).split('\n')

            for (let indice = 1; indice < apresentadas.length; indice++) {
                const anterior = apresentadas[indice - 1]
                const atual = apresentadas[indice]

                expect(
                    compararVersoes(anterior, atual),
                    `${anterior} deveria vir depois de ${atual}`
                ).to.be.at.least(0)
            }
        })
    })

    describe('ehVersaoDeProducao e temPlataforma', function () {
        it('reconhece versao de producao', function () {
            expect(ehVersaoDeProducao('1.4.2-windows-2016')).to.be.true
            expect(ehVersaoDeProducao('1.80')).to.be.true
            expect(ehVersaoDeProducao('FNX-5220-windows')).to.be.false
            expect(ehVersaoDeProducao('1.6.0-rc1')).to.be.false
        })

        it('reconhece a plataforma da tag', function () {
            expect(temPlataforma('5.4.9-linux', 'linux')).to.be.true
            expect(temPlataforma('5.4.9-linux', 'windows')).to.be.false
            expect(temPlataforma('1.4.2-windows-2016', 'windows')).to.be.true
            expect(temPlataforma('5.4.9-linux', null)).to.be.true
        })
    })
})
