import unittest

from cad_parser import threeshape

from pathlib import Path

class SkipTest:
    def __init__(self, condition, description):
        self.condition = condition
        self.description = description

    def __call__(self, func):
        if not self.condition:
            return unittest.skip(self.description)(func)
        return func

@SkipTest(Path('tests/samples/3shape').exists(), "Lokal tests only")
class Threeshape(unittest.TestCase):
    def test_kappe(self):
        filePath = Path('tests/samples/3shape/01_Kappe/24-07-23_Kappen_3ox/24-07-23_Kappen_3ox.3ox')
        order = threeshape.parse_3ox(filePath)

        self.assertEqual(order.format, '3ox')
        self.assertEqual(order.project, '24-07-23_Kappen_3ox')
        self.assertEqual(order.comment, '')
        self.assertEqual(len(order.elements), 5)
        for idx,element in enumerate(order.elements):
            if idx == 0:
                self.assertEqual(element.file_name, '24-07-23_Kappen_3ox_0.stl')
            if idx == 1:
                self.assertEqual(element.file_name, '24-07-23_Kappen_3ox_1.stl')
            if idx == 2:
                self.assertEqual(element.file_name, '24-07-23_Kappen_3ox_2.stl')
            if idx == 3:
                self.assertEqual(element.file_name, '24-07-23_Kappen_3ox_3.stl')
            if idx == 4:
                self.assertEqual(element.file_name, '24-07-23_Kappen_3ox_4.stl')

        self.assertEqual(len(order.scan_files), 2)
        for scan_file in order.scan_files:
            if scan_file.type == 'Preparation':
                self.assertEqual(scan_file.file_name, 'PreparationScan.dcm')
            if scan_file.type == 'AntagonistModel':
                self.assertEqual(scan_file.file_name, 'AntagonistScan.dcm')

    def test_parse_die(self):
        filePath = Path('tests/samples/3shape/01_Kappe/24-07-23_Kappen_3ox/24-07-23_Kappen_3ox.3ox')
        order = threeshape.parse_3ox(filePath)

        for idx, model in enumerate(order.models):
            if idx == 0:
                self.assertEqual(model.file_name, '24-07-23_Kappen_3ox_0_Die_9.stl')
            if idx == 1:
                self.assertEqual(model.file_name, '24-07-23_Kappen_3ox_1_Die_11.stl')
            if idx == 2:
                self.assertEqual(model.file_name, '24-07-23_Kappen_3ox_1_Die_8.stl')
            if idx == 3:
                self.assertEqual(model.file_name, '24-07-23_Kappen_3ox_2_Die_7.stl')

    def test_brueke(self):
        filePath = Path('tests/samples/3shape/08_Sekundärteil_Brücke/single_3shape_154202/Tech_01_Bork_Gruenter_20230614_0900.3ox')
        order = threeshape.parse_3ox(filePath)

        self.assertEqual(order.format, '3ox')
        self.assertEqual(order.project, 'Bork_Gruenter')
        self.assertEqual(order.comment, '')
        self.assertEqual(len(order.elements), 2)
        for idx,element in enumerate(order.elements):
            if idx == 0:
                self.assertEqual(element.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_0.stl')
            if idx == 1:
                self.assertEqual(element.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_1.stl')

        self.assertEqual(len(order.scan_files), 1)
        for scan in order.scan_files:
            if scan.type == 'Preparation':
                self.assertEqual(scan.file_name, 'PreparationScan.dcm')

        for idx, model in enumerate(order.models):
            if idx == 0:
                self.assertEqual(model.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_0_Die_22.stl')
            if idx == 1:
                self.assertEqual(model.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_1_Die_27.stl')

    def test_is_supported(self):
        # Positive test cases
        self.assertTrue(threeshape.is_supported(Path('tests/samples/3shape/01_Kappe/24-07-23_Kappen_3ox')))
        self.assertTrue(threeshape.is_supported(Path('tests/samples/3shape/08_Sekundärteil_Brücke/single_3shape_154202')))
        self.assertTrue(threeshape.is_supported(Path('tests/samples/3shape/08_Verblendete_Brücke/179439')))

        # Negative test cases
        self.assertFalse(threeshape.is_supported(Path('tests/samples/exocad/01_Kappe/Menne_Kappe')))
        self.assertFalse(threeshape.is_supported(Path('tests/samples/exocad/02_Krone/156094_krone_inkl_Abutment')))

    def test_parse(self):
        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/08_Sekundärteil_Brücke/single_3shape_154202'))

        self.assertEqual(threeshape_file, Path('tests/samples/3shape/08_Sekundärteil_Brücke/single_3shape_154202/Tech_01_Bork_Gruenter_20230614_0900.3ox'))

        self.assertEqual(order.format, '3ox')
        self.assertEqual(order.project, 'Bork_Gruenter')
        self.assertEqual(order.comment, '')
        self.assertEqual(len(order.elements), 2)
        for idx,element in enumerate(order.elements):
            if idx == 0:
                self.assertEqual(element.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_0.stl')
            if idx == 1:
                self.assertEqual(element.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_1.stl')

        self.assertEqual(len(order.scan_files), 1)
        for scan in order.scan_files:
            if scan.type == 'Preparation':
                self.assertEqual(scan.file_name, 'PreparationScan.dcm')

        for idx, model in enumerate(order.models):
            if idx == 0:
                self.assertEqual(model.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_0_Die_22.stl')
            if idx == 1:
                self.assertEqual(model.file_name, 'Tech_01_Bork_Gruenter_20230614_0900_1_Die_27.stl')

    def test_element_files_exist(self):
        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/02_Krone/180148'))

        for element in order.elements:
            self.assertIsNotNone(element.file_name)

    def test_element_type_can_be_none(self):
        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/03_Teleskop/164182'))

        for element in order.elements:
            self.assertIsNotNone(element.type)

        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/02_Krone/180148'))

        for element in order.elements:
            self.assertIsNone(element.type)

    def test_abutment_alias(self):
        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/09_Abutment/180066'))

        for element in order.elements:
            for tooth in element.teeth:
                if tooth.fdi == 46:
                    self.assertEqual(tooth.implant_system, 'Abutment_MEG_3.555_GH05')
                if tooth.fdi == 45:
                    self.assertEqual(tooth.implant_system, 'Abutment_MEG_3.555_GH05')
                if tooth.fdi == 14:
                    self.assertEqual(tooth.implant_system, 'Abutment_MEG_3.555_GH05')
                if tooth.fdi == 17:
                    self.assertEqual(tooth.implant_system, 'Abutment_MEG_3.555_GH05')

        
        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/09_Abutment/180608'))

        for element in order.elements:
            for tooth in element.teeth:
                if tooth.fdi == 14:
                    self.assertEqual(tooth.implant_system, 'Abutment_MEG_3.555_GH05')
                if tooth.fdi == 36:
                    self.assertEqual(tooth.implant_system, 'Abutment_MEG_3.555_GH05')

        threeshape_file, order = threeshape.parse(Path('tests/samples/3shape/09_Abutment/184819'))

        for element in order.elements:
            for tooth in element.teeth:
                if tooth.fdi == 16:
                    self.assertEqual(tooth.implant_system, 'BTI® 23.2 INTERNA UNIVERSAL_INPSPU0_65')
                if tooth.fdi == 13:
                    self.assertEqual(tooth.implant_system, 'BTI® 23.2 INTERNA UNIVERSAL_INPSPU0_65')