// config/parser/CustomerInfoParser.kt package com.complycube.reactnative.config.parser import com.complycube.reactnative.config.helper.MetadataTemplateProcessor import com.complycube.reactnative.config.helper.CustomerInfoFieldMapper import com.complycube.sdk.common.data.Country import com.complycube.sdk.data.remote.model.response.ComponentFormat import com.complycube.sdk.data.remote.model.response.ComponentType import com.complycube.sdk.data.remote.model.response.Constraint import com.complycube.sdk.data.remote.model.response.QuestionItemComponentFormat import com.complycube.sdk.data.remote.model.response.QuestionOptionsItem import com.complycube.sdk.common.data.CustomerInfoField import com.complycube.sdk.common.data.CustomerInfoPersonField import com.complycube.sdk.common.data.CustomerInfoCompanyField import com.complycube.sdk.common.data.CustomerInfoDetail import com.complycube.sdk.common.data.Stage.CustomStage.CustomerInfo import com.complycube.reactnative.logging.Logger import com.complycube.reactnative.logging.LogTag class CustomerInfoParser( private val fieldMapper: CustomerInfoFieldMapper, private val templateProcessor: MetadataTemplateProcessor ) { fun parseCustomerInfo(data: Map): CustomerInfo { val title = data["title"] as? String ?: "" val fields = data["customerInfoFields"] as? List<*> ?: emptyList() // 1) Top-level templates if present var metadataTemplates: List> = (data["metadataTemplates"] as? List<*>)?.filterIsInstance>() ?: emptyList() // 2) If not at top-level, look for templates nested under any field object if (metadataTemplates.isEmpty()) { for (field in fields) { val map = field as? Map<*, *> ?: continue val nested = map["metadataTemplates"] as? List<*> if (!nested.isNullOrEmpty()) { @Suppress("UNCHECKED_CAST") metadataTemplates = nested.filterIsInstance>() break } } } val customerInfoFields = mutableListOf() for (field in fields) { when (field) { is String -> { fieldMapper.mapStringField(field)?.let { customerInfoFields.add(it) } } is Map<*, *> -> { @Suppress("UNCHECKED_CAST") val fieldMap = field as Map parseComplexField(fieldMap, customerInfoFields, metadataTemplates) } } } Logger.d(LogTag.SETTINGS) { "Settings resolved: ${customerInfoFields.size}" } return CustomerInfo( title = title, customerInfoFields = customerInfoFields ) } private fun parseComplexField( field: Map, customerInfoFields: MutableList, metadataTemplates: List> ) { // Parse details if ("details" in field) { parseDetailsField(field, customerInfoFields) } // Parse metadata if ("metadata" in field) { parseMetadataField(field, customerInfoFields, metadataTemplates) } } private fun parseDetailsField( field: Map, customerInfoFields: MutableList ) { val details = field["details"] as? List<*> ?: return for (detail in details) { val detailMap = detail as? Map<*, *> ?: continue // Person details if ("person" in detailMap) { val personFields = fieldMapper.mapPersonFields(detailMap["person"] as List<*>) customerInfoFields.add(CustomerInfoField.Details(CustomerInfoDetail.Person(personFields))) } // Company details if ("company" in detailMap) { val companyFields = fieldMapper.mapCompanyFields(detailMap["company"] as List<*>) customerInfoFields.add(CustomerInfoField.Details(CustomerInfoDetail.Company(companyFields))) } } } private fun parseMetadataField( field: Map, customerInfoFields: MutableList, metadataTemplates: List> ) { val metadataList = field["metadata"] as? List<*> ?: return var countrySelectKey = "" for (meta in metadataList) { val metaMap = meta as? Map<*, *> ?: continue @Suppress("UNCHECKED_CAST") val metadataMap = metaMap as Map val key = metadataMap["key"] as? String ?: continue val question = metadataMap["question"] as? String ?: "" val componentType = try { ComponentType.valueOf(metadataMap["componentType"] as String) } catch (e: Exception) { continue } val formatMap = metadataMap["format"] as? Map<*, *> val format = formatMap?.let { QuestionItemComponentFormat( type = ComponentFormat.valueOf(it["type"] as String), validation = it["validation"] as String ) } val optionsList = metadataMap["options"] as? List<*> val options = optionsList?.map { val optionMap = it as Map<*, *> QuestionOptionsItem( label = optionMap["label"] as String, value = optionMap["value"] as String ) } val constraintMap = metadataMap["constraint"] as? Map<*, *> val constraint = constraintMap?.let { Constraint(it["expression"] as String) } val required = metadataMap["required"] as? Boolean ?: false val description = metadataMap["description"] as? String if (componentType == ComponentType.MULTI_SELECT_COUNTRY) { countrySelectKey = key val filteredCountries = parseCountrySelection(metadataMap) val countryOptions = getCountryOptions(filteredCountries) customerInfoFields.add( CustomerInfoField.Metadata( key = key, question = question, componentType = componentType, format = format, options = countryOptions, constraint = constraint, required = required, description = description ) ) // Process templates for filtered countries templateProcessor.processCountryTemplates( filteredCountries, countrySelectKey, metadataTemplates, customerInfoFields ) } else { customerInfoFields.add( CustomerInfoField.Metadata( key = key, question = question, componentType = componentType, format = format, options = options, constraint = constraint, required = required, description = description ) ) } } } private fun parseCountrySelection(metadataMap: Map): List { val allCountries: List = enumValues().toList() val countriesObject = metadataMap["countries"] as? Map<*, *> return when { countriesObject != null -> { val mode = countriesObject["mode"] as? String ?: "inclusion" val list = countriesObject["list"] as? List<*> ?: emptyList() val includedEnums: List = list.mapNotNull { code -> code?.toString()?.let { enumCode -> try { enumValues().firstOrNull { it.name == enumCode } } catch (e: Exception) { null } } } when (mode) { "inclusion" -> includedEnums "exclusion" -> allCountries.filterNot { excluded -> includedEnums.any { it.name == excluded.name } } else -> allCountries } } else -> allCountries } } private fun getCountryOptions(filteredCountries: List): List { return filteredCountries.map { QuestionOptionsItem( value = it.name, label = it.nameResourceId.toString() ) } } }