import unittest

from cad_parser import exocad

from pathlib import Path
import logging

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/exocad').exists(), "Lokal tests only")
class TestExocad(unittest.TestCase):
    logger = logging.getLogger(__name__)
    logging.basicConfig(format = '%(asctime)s %(module)s %(levelname)s: %(message)s', datefmt = '%m/%d/%Y %I:%M:%S %p', level = logging.INFO)

    def test_is_supported(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                if project.name == 'MissingConstructionInfo' or project.is_file():
                    continue
                
                self.assertTrue(exocad.is_supported(project), f"{project} is not supported")
                
    def test_parse_dental_project(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                if project.name == 'MissingConstructionInfo' or project.is_file():
                    continue
                dental_project_path = next(project.glob('*.dental[pP]roject'))
                patient = exocad.parse_dental_project(dental_project_path)
                self.assertIsNotNone(patient.id)
                self.assertIsNotNone(patient.last_name)

    def test_parse_construction_info(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                construction_info_path = next(project.glob('*.constructionInfo'), None)
                if construction_info_path:
                    order = exocad.parse_construction_info(construction_info_path)

    def test_parse_model_info(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                model_info_path = next(project.glob('*.modelInfo'), None)
                if model_info_path:
                    order = exocad.parse_model_info(model_info_path)
                    
    def test_parse_scan_info(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                scan_info_path = next(project.glob('*.scanInfo'), None)
                if scan_info_path:
                    order = exocad.parse_scan_info(scan_info_path)

    def test_parse_partial_info(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                partial_info_path = next(project.glob('*.partialInfo'), None)
                if partial_info_path:
                    order = exocad.parse_partial_info(partial_info_path)
    
    def test_parse(self):
        project_types = Path('tests/samples/exocad').iterdir()
        project_types = filter(lambda x: x.is_dir(), project_types)
        for project_type in project_types:
            for project in project_type.iterdir():
                if project.name == 'MissingConstructionInfo' or project.is_file():
                    continue
                order = exocad.parse(project)

    def test_parse_partial_clamp(self):
        project = Path('tests/samples/exocad/32_Modellguss/00001_Viktor_Klammer_MG_-2025-04-03_010/Viktor_Klammer_MG_-2025-04-03-lowerjaw.partialInfo')
        elements = exocad.parse_partial_info(project)
        for element in elements:
            self.assertEqual(element.type, 'modelclip')

    def test_parse_partial_framework(self):
        project = Path('tests/samples/exocad/32_Modellguss/00001_Viktor_Tertiaer_-2025-04-02_010/Viktor_Tertiaer_-2025-04-02-upperjaw.partialInfo')
        elements = exocad.parse_partial_info(project)
        for element in elements:
            self.assertEqual(element.type, 'framework')

    def test_parse_construction_info(self):
        project = Path('tests/samples/exocad/32_Modellguss/00001_Viktor_Tertiaer_-2025-04-03_008_aus_CAD/Viktor_Tertiaer_-2025-04-03.constructionInfo')
        order = exocad.parse_construction_info(project)
        self.logger.info(order)
        for element in order.elements:
            self.assertEqual(element.type,  'MergedBridgeSLM')

    def test_construction_info_with_model_info(self):
        project = Path('tests/samples/exocad/33_Construction+Modell/03369_Luedke_Ralf_-2025-04-11_001')
        _, _, _, _, _, order = exocad.parse(project)
        self.logger.info(order.models)
        self.assertGreater(len(order.elements), 0)
        self.assertGreater(len(order.models), 0)

    def test_abutment_type(self):
        project = Path('tests/samples/exocad/09_Abutment/154711')
        _, _, _, _, _, order = exocad.parse(project)
        self.assertEqual(order.elements[0].teeth[0].implant_system, 'medentika_preface-t_conid : PreFace_T9000-R : T9000-R')

        project = Path('tests/samples/exocad/09_Abutment/156094_krone_inkl_Abutment')
        _, _, _, _, _, order = exocad.parse(project)
        self.assertEqual(order.elements[0].teeth[0].implant_system, 'medentika_preface-l_conid : PreFace_L9810-16R-1 : L9810-16R-1')
        self.assertEqual(order.elements[1].teeth[0].implant_system, None)

        project = Path('tests/samples/exocad/EdgeCases/AbutmentAliasNotDetected')
        _, _, _, _, _, order = exocad.parse(project)
        self.assertEqual(order.elements[0].teeth[0].implant_system, 'medentika_preface-n_conid : PreFace_N9810-16R-1 : N9810-16R-1')

    def test_parse_complex_partial_framework(self):
        project = Path('tests/samples/exocad/EdgeCases/PartialFramework')
        found_dentalProject = next(project.glob('*.dental[pP]roject'), False)
        found_constructionInfo = next(project.glob('*.construction[iI]nfo'), False)
        found_modelInfo = next(project.glob('*.model[iI]nfo'), False)
        found_scanInfo = next(project.glob('*.scan[iI]nfo'), False)
        found_partialInfo = next(project.glob('*.partial[iI]nfo'), False)

        print('found_dentalProject:', found_dentalProject)
        print('found_constructionInfo:', found_constructionInfo)
        print('found_modelInfo:', found_modelInfo)
        print('found_scanInfo:', found_scanInfo)
        print('found_partialInfo:', found_partialInfo)
