import unittest

from lib.catalogo_versoes import (
    CATALOGO,
    CATALOGO_POR_CHAVE,
    TIPO_DOCKER,
    TIPO_DOWNLOAD,
    TIPO_GIT,
    caminho_projeto_da_imagem,
    extrair_versoes_da_listagem,
    filtrar_catalogo,
    ha_storybook_correspondente,
    selecionar_ultima_versao,
)
from lib.sistemas_docker import SISTEMAS_DOCKER, REGISTRO_EMPRESA


class TestCaminhoProjetoDaImagem(unittest.TestCase):
    def test_remove_o_nome_da_imagem(self):
        self.assertEqual(
            caminho_projeto_da_imagem("microuniverso/mufenix/enterprise/enterprise"),
            "microuniverso/mufenix/enterprise"
        )

    def test_ignora_barras_sobrando(self):
        self.assertEqual(
            caminho_projeto_da_imagem("/microuniverso/mufenix/cassini/cassini/"),
            "microuniverso/mufenix/cassini"
        )

    def test_devolve_none_sem_imagem_ou_sem_caminho(self):
        self.assertIsNone(caminho_projeto_da_imagem(None))
        self.assertIsNone(caminho_projeto_da_imagem(""))
        self.assertIsNone(caminho_projeto_da_imagem("imagem-solta"))


class TestSelecionarUltimaVersao(unittest.TestCase):
    def test_prefere_versao_oficial_a_branch(self):
        tags = ["FNX-5220-windows", "1.4.2-windows-2016", "master"]

        self.assertEqual(selecionar_ultima_versao(tags), "1.4.2-windows-2016")

    def test_escolhe_a_maior_versao(self):
        tags = ["5.4.9-linux", "5.4.12-linux", "5.3.0-linux"]

        self.assertEqual(selecionar_ultima_versao(tags), "5.4.12-linux")

    def test_respeita_a_plataforma(self):
        tags = ["5.4.12-linux", "5.4.9-windows"]

        self.assertEqual(selecionar_ultima_versao(tags, "windows"), "5.4.9-windows")
        self.assertEqual(selecionar_ultima_versao(tags, "linux"), "5.4.12-linux")

    def test_sem_tag_da_plataforma_devolve_none(self):
        self.assertIsNone(selecionar_ultima_versao(["5.4.12-linux"], "windows"))

    def test_cai_para_a_mais_recente_quando_nao_ha_versao_oficial(self):
        # Caso do Whatsapp Bot, publicado por branch
        tags = ["FNX-5220", "FNX-5320"]

        self.assertEqual(selecionar_ultima_versao(tags), "FNX-5320")

    def test_lista_vazia_devolve_none(self):
        self.assertIsNone(selecionar_ultima_versao([]))
        self.assertIsNone(selecionar_ultima_versao(None))


class TestExtrairVersoesDaListagem(unittest.TestCase):
    def test_ordena_da_versao_mais_recente_para_a_mais_antiga(self):
        html = (
            '<a href="srvcusto118.zip">srvcusto118.zip</a>'
            '<a href="srvcusto9.zip">srvcusto9.zip</a>'
            '<a href="srvcusto120.zip">srvcusto120.zip</a>'
        )

        versoes = extrair_versoes_da_listagem(html, r'href="(srvcusto(\d+)\.zip)"')

        self.assertEqual(
            versoes,
            [("srvcusto120.zip", "120"), ("srvcusto118.zip", "118"), ("srvcusto9.zip", "9")]
        )

    def test_listagem_sem_arquivo_devolve_lista_vazia(self):
        self.assertEqual(extrair_versoes_da_listagem("<html></html>", r'href="(srvcusto(\d+)\.zip)"'), [])
        self.assertEqual(extrair_versoes_da_listagem(None, r'href="(srvcusto(\d+)\.zip)"'), [])


class TestFiltrarCatalogo(unittest.TestCase):
    def test_sem_filtro_devolve_tudo_menos_os_storybooks(self):
        storybooks = [entrada for entrada in CATALOGO if entrada.storybook]

        self.assertTrue(storybooks, "o catalogo deveria ter storybooks para este teste valer")
        self.assertEqual(len(filtrar_catalogo()), len(CATALOGO) - len(storybooks))

    def test_com_a_flag_devolve_tambem_os_storybooks(self):
        self.assertEqual(len(filtrar_catalogo(incluir_storybooks=True)), len(CATALOGO))

    def test_storybook_nao_entra_nem_quando_o_filtro_casa(self):
        self.assertEqual(filtrar_catalogo("storybook"), [])

        chaves = [entrada.chave for entrada in filtrar_catalogo("storybook", incluir_storybooks=True)]

        self.assertIn("vendasStorybook", chaves)

    def test_filtro_de_sistema_nao_traz_o_storybook_dele(self):
        chaves = [entrada.chave for entrada in filtrar_catalogo("centralDeCadastros")]

        self.assertEqual(chaves, ["centralDeCadastros"])

    def test_filtra_por_chave_nome_ou_imagem(self):
        chaves = [entrada.chave for entrada in filtrar_catalogo("enterprise")]

        self.assertIn("enterprise", chaves)
        self.assertIn("enterpriseRenderizador", chaves)

        self.assertEqual([e.chave for e in filtrar_catalogo("wppconnect")], ["muWhatsapp"])

    def test_filtro_sem_correspondencia_devolve_lista_vazia(self):
        self.assertEqual(filtrar_catalogo("nao-existe-esse-sistema"), [])


class TestHaStorybookCorrespondente(unittest.TestCase):
    def test_reconhece_filtro_que_so_casa_com_storybook(self):
        self.assertTrue(ha_storybook_correspondente("storybook"))
        self.assertTrue(ha_storybook_correspondente("vendasStorybook"))

    def test_nao_reconhece_filtro_de_outro_sistema(self):
        self.assertFalse(ha_storybook_correspondente("microkafka"))
        self.assertFalse(ha_storybook_correspondente("nao-existe-esse-sistema"))


class TestConsistenciaDoCatalogo(unittest.TestCase):
    def test_chaves_sao_unicas(self):
        self.assertEqual(len(CATALOGO_POR_CHAVE), len(CATALOGO))

    def test_toda_entrada_tem_como_ser_consultada(self):
        for entrada in CATALOGO:
            with self.subTest(chave=entrada.chave):
                if entrada.tipo == TIPO_DOCKER:
                    self.assertTrue(entrada.imagem, "entrada docker sem imagem")
                    self.assertTrue(entrada.caminho_projeto, "imagem sem caminho de projeto")
                    self.assertTrue(entrada.localizacao_esperada.startswith(REGISTRO_EMPRESA))
                elif entrada.tipo == TIPO_GIT:
                    self.assertTrue(entrada.projeto, "entrada git sem id de projeto")
                else:
                    self.assertEqual(entrada.tipo, TIPO_DOWNLOAD)
                    self.assertTrue(entrada.listagem)
                    self.assertTrue(entrada.padrao_arquivo)

    def test_cobre_as_imagens_fixas_do_catalogo_de_sistemas_docker(self):
        """
        Toda imagem com endereco fixo em sistemas_docker.py precisa estar aqui.

        Evita que um sistema novo entre na implantacao e fique de fora do
        inventario de versoes sem ninguem perceber.
        """

        imagens_do_catalogo = {
            entrada.imagem for entrada in CATALOGO if entrada.tipo == TIPO_DOCKER
        }

        for sistema in SISTEMAS_DOCKER:
            if not sistema.imagem:
                continue

            imagem_sem_registro = sistema.imagem.replace(f"{REGISTRO_EMPRESA}/", "")

            with self.subTest(sistema=sistema.chave):
                self.assertIn(imagem_sem_registro, imagens_do_catalogo)


if __name__ == "__main__":
    unittest.main()
