package com.ikon.projectmanagement.service.etl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.stereotype.Component;

import com.ikon.connector.dto.response.FieldsConfigDto;
import com.ikon.connector.spi.ConnectorDataSync;
import com.ikon.projectmanagement.entity.Grade;
import com.ikon.projectmanagement.repository.GradeRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

/**
 * GradeConnector: Maps external grade/salary grade data to local Grade entity
 * 
 * This connector syncs grade information from an external HR system or database.
 * It handles field mapping, type conversion, and persistence of grade records.
 */
@Component
@RequiredArgsConstructor
public class GradeConnector implements ConnectorDataSync {

    private final GradeRepository gradeRepository;

    /**
     * Define the configuration for fields that will be synced from external source.
     * This specifies the external field names, labels, and their data types.
     */
    @Override
    public List<FieldsConfigDto> getFieldsConfig() {
        List<FieldsConfigDto> fieldsConfig = new ArrayList<>();

        fieldsConfig.add(FieldsConfigDto.builder()
            .key("id")
            .label("Grade ID")
            .type("string")
            .build());

        fieldsConfig.add(FieldsConfigDto.builder()
            .key("accountId")
            .label("Account ID")
            .type("string")
            .build());

        fieldsConfig.add(FieldsConfigDto.builder()
            .key("grade")
            .label("Grade")
            .type("string")
            .build());

        return fieldsConfig;
    }

    /**
     * Returns the module name for this connector.
     * Used for identification and logging purposes.
     */
    @Override
    public String getModule() {
        return "Grade";
    }

    /**
     * Core method that processes incoming grade data from external source.
     * 
     * Process flow:
     * 1. Extract and parse fields from Map
     * 2. Convert data types using utility methods
     * 3. Build Grade entity
     * 4. Save to repository
     * 
     * @param payload List of Map objects containing grade data from external source
     */
    @Override
    @Transactional
    public void syncBatch(List<Map<String, Object>> payload) {
        payload.stream()
            .forEach(data -> {
                try {
                    UUID gradeId = parseUUID(data.get("id"));
                    UUID accountId = parseUUID(data.get("accountId"));
                    String gradeName = toStr(data.get("grade"));
                    
                    // Skip if required fields are missing
                    if (gradeId == null || gradeName == null) {
                        System.err.println("Skipping grade record: missing required fields (id or grade)");
                        return;
                    }
                    
                    // Build Grade entity with mapped fields
                    Grade grade = Grade.builder()
                        .id(gradeId)
                        .accountId(accountId)
                        .grade(gradeName)
                        .build();
                    
                    // Save the grade entity to repository
                    gradeRepository.save(grade);
                    
                } catch (Exception e) {
                    // Log error but continue processing other records
                    System.err.println("Error syncing grade: " + e.getMessage());
                }
            });
    }

    // ============ Utility Methods for Type Conversion ============

    /**
     * Parse UUID from Object safely.
     * Returns null if value is null or cannot be parsed as UUID.
     */
    private UUID parseUUID(Object value) {
        if (value == null) return null;
        try {
            return UUID.fromString(value.toString());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Convert Object to String safely.
     * Returns null if value is null, otherwise returns String representation.
     */
    private String toStr(Object value) {
        return value != null ? String.valueOf(value) : null;
    }
}
