package incheon.sgp.rst.service.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ibm.icu.math.BigDecimal;

import incheon.uis.ums.util.UisApplicationContextProvider;
import incheon.uis.ums.util.UisConfigUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import incheon.sgp.rst.service.RstFacilityService;
import incheon.sgp.rst.util.RstConfigUtils;
//import incheon.uis.cm.mapper.CommonCodeMapper;
import incheon.uis.ums.service.UisFacilityService;

/**
 * 시설물 서비스 구현체
 *
 * @author 이재룡
 * @since 2025.09.02
 * @version 2.0.0
 */
@Slf4j
@Service
public class RstFacilityServiceImpl extends RstBaseService implements RstFacilityService {

    @Autowired
    private UisApplicationContextProvider applicationContextProvider;

    @Autowired
    private RstConfigUtils RstConfigUtils;

//    @Autowired
//    private CommonCodeMapper commonCodeMapper;

	@Override
	public List<?> selectList(Object requestVO) throws Exception {
		// requestModel가 동적 오브젝트일 때 TypeId 속성 값
        String typeId = "";
        String typeGb = "";
        try {
            // getTypeId() 메서드가 있으면 호출
            typeId = (String) requestVO.getClass().getMethod("getTypeId").invoke(requestVO);
            typeGb = (String) requestVO.getClass().getMethod("getTypeGb").invoke(requestVO);
        } catch (Exception e) {
            try {
                // getTypeId()가 없으면 getTypeId 필드 직접 접근 시도
                typeId = (String) requestVO.getClass().getField("TypeId").get(requestVO);
                typeGb = (String) requestVO.getClass().getField("TypeGb").get(requestVO);
            } catch (Exception ex) {
                // 필드도 없으면 빈 값 유지
                typeId = "";
                typeGb = "";
            }
        } 
        
        // typeId + "ListMapper" 형태의 Mapper를 동적으로 가져와서 selectContructionList 호출
        if (typeId == null || typeId.isEmpty()) {
            throw new IllegalArgumentException("typeId가 비어있습니다.");
        }
        
        // 주입받은 ApplicationContext 사용
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }
        
        String [] splitTypeId = StringUtils.split(typeId, ":");
        typeId = Arrays.stream(splitTypeId).skip(1).findFirst().orElse(typeId);
        
        // typeId + "ListMapper" 형태의 리스트 검색 전용 매퍼 사용
        String mapperBeanName = Character.toLowerCase(typeId.charAt(0)) + typeId.substring(1) + "ListMapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);
        
        String methodName = "constructions".equals(typeGb) ? "selectContructionList" : "selectFacilityList";

        // 매퍼의 selectContructionList 메서드 찾기
        java.lang.reflect.Method[] methods = mapper.getClass().getMethods();
        java.lang.reflect.Method targetMethod = null;
        for (java.lang.reflect.Method method : methods) {
            if (methodName.equals(method.getName())) {
                targetMethod = method;
                break;
            }
        }
        
        if (targetMethod == null) {
            throw new IllegalStateException(mapperBeanName + "에서 "+methodName+" 메소드를 찾을 수 없습니다.");
        }
        
        Object result = targetMethod.invoke(mapper, requestVO);
        return (List<?>) result;
	}

	@Override
	public int selectListTotalCount(Object requestVO) throws Exception {
		String typeId = "";
		String typeGb = "";
        try {
            typeId = (String) requestVO.getClass().getMethod("getTypeId").invoke(requestVO);
			typeGb = (String) requestVO.getClass().getMethod("getTypeGb").invoke(requestVO);
        } catch (Exception e) {
            typeId = "";
			typeGb = "";
        }
        if (typeId == null || typeId.isEmpty()) {
            throw new IllegalArgumentException("typeId가 비어있습니다.");
        }
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }
        
        String [] splitTypeId = StringUtils.split(typeId, ":");
        typeId = Arrays.stream(splitTypeId).skip(1).findFirst().orElse(typeId);
        String mapperBeanName = Character.toLowerCase(typeId.charAt(0)) + typeId.substring(1) + "ListMapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);

		String methodName = "constructions".equals(typeGb) ? "selectContructionListTotalCount" : "selectFacilityListTotalCount";

        java.lang.reflect.Method[] methods = mapper.getClass().getMethods();
        java.lang.reflect.Method targetMethod = null;
        for (java.lang.reflect.Method method : methods) {
            if (methodName.equals(method.getName())) {
                targetMethod = method;
                break;
            }
        }
        if (targetMethod == null) {
            throw new IllegalStateException(mapperBeanName + "에서 "+methodName+" 메소드를 찾을 수 없습니다.");
        }
        Object result = targetMethod.invoke(mapper, requestVO);
        return (result instanceof Integer) ? (Integer) result : Integer.parseInt(String.valueOf(result));
	}

	@Override
	public Object selectDetail(String typeId, Object requestModel) throws Exception {

        Map<String, Object> paramMap = new HashMap<>();

        // requestModel에서 모든 필드를 paramMap으로 복사
        for (Field field : requestModel.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            Object value = field.get(requestModel);
            if (value != null) {
                paramMap.put(field.getName(), value);
            }
        }

        log.debug("상세조회 파라미터: typeId={}, requestModel={}, paramMap={}", typeId, requestModel.getClass().getSimpleName(), paramMap);

        if (typeId == null || typeId.isEmpty()) {
            throw new IllegalArgumentException("typeId가 비어있습니다.");
        }

        // 주입받은 ApplicationContext 사용
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }

        String[] splitTypeId = StringUtils.split(typeId, ":");
		typeId = Arrays.stream(splitTypeId).skip(1).findFirst().orElse(typeId);
        String mapperBeanName = Character.toLowerCase(typeId.charAt(0)) + typeId.substring(1) + "Mapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);

        log.debug("매퍼 빈: {}", mapperBeanName);

        // 1. 매퍼의 모든 메소드 중 selectByPrimaryKey 찾기
        Method[] methods = mapper.getClass().getMethods();
        Method targetMethod = null;
        for (Method method : methods) {
            if ("selectByPrimaryKey".equals(method.getName())) {
                targetMethod = method;
                break;
            }
        }
        if (targetMethod == null) {
            throw new IllegalStateException(mapperBeanName + "에서 selectByPrimaryKey 메소드를 찾을 수 없습니다.");
        }
        
        // 3. 메소드 호출
        try {
            log.debug("매퍼 메서드 호출: {}.selectByPrimaryKey()", mapperBeanName);
            //Object result = targetMethod.invoke(mapper, args);
            Long gid = (Long) paramMap.get("gid");
            Object result = targetMethod.invoke(mapper, new Object[]{gid});
            log.debug("매퍼 메서드 호출 완료: 결과 타입 = {}", result != null ? result.getClass().getSimpleName() : "null");
            return result;
        } catch (Exception e) {
            log.error("매퍼 메서드 호출 중 오류 발생: {}", e.getMessage(), e);
            throw new Exception("매퍼 메서드 호출 중 오류 발생: " + e.getMessage(), e);
        }
	}


    @Override
    @SuppressWarnings("unchecked")
    @Transactional
    public Object insert(Object requestModel) throws Exception {
        String typeId = "";
        
        // typeId 추출
        try {
            typeId = (String) requestModel.getClass().getMethod("getTypeId").invoke(requestModel);
        } catch (Exception e) {
            log.debug("typeId 추출 실패: {}", e.getMessage());
        }
        
        log.debug("등록 파라미터: typeId={}, requestModel={}", typeId, requestModel.getClass().getSimpleName());
        
        if (typeId == null || typeId.isEmpty()) {
            throw new IllegalArgumentException("typeId가 비어있습니다.");
        }

        
        
        // 주입받은 ApplicationContext 사용
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }
        
        String[] splitTypeId = StringUtils.split(typeId, ":");
		typeId = Arrays.stream(splitTypeId).skip(1).findFirst().orElse(typeId);
        String mapperBeanName = Character.toLowerCase(typeId.charAt(0)) + typeId.substring(1) + "Mapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);
        
        log.debug("매퍼 빈: {}", mapperBeanName);
        
        // 매퍼의 insert 메서드 찾기
        Method[] methods = mapper.getClass().getMethods();
        Method targetMethod = null;
        for (Method method : methods) {
            if ("insert".equals(method.getName())) {
                targetMethod = method;
                break;
            }
        }
        
        if (targetMethod == null) {
            throw new IllegalStateException(mapperBeanName + "에서 insert 메소드를 찾을 수 없습니다.");
        }
        
        //TODO: 임시 ObjectId 생성 로직 구현 필요 - 2025-09-17 불필요 이재룡
        //generateObjectId(requestModel, typeId);
        
        // 매퍼 메서드 호출
        Object result = targetMethod.invoke(mapper, requestModel);
        return result;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object update(Object requestModel) throws Exception {
        String typeId = "";
        Map<String, Object> paramMap = new HashMap<>();
        
        // requestModel에서 모든 필드를 paramMap으로 복사
        for (Field field : requestModel.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            Object value = field.get(requestModel);
            if (value != null) {
                paramMap.put(field.getName(), value);
            }
        }
        
        // typeId 추출
        try {
            //typeId = (String) requestModel.getClass().getMethod("getTypeId").invoke(requestModel);
            typeId = requestModel.getClass().getSimpleName();
        } catch (Exception e) {
            log.debug("typeId 추출 실패: {}", e.getMessage());
        }
        
        log.debug("수정 파라미터: typeId={}, requestModel={}, paramMap={}", typeId, requestModel.getClass().getSimpleName(), paramMap);
        
        if (typeId == null || typeId.isEmpty()) {
            throw new IllegalArgumentException("typeId가 비어있습니다.");
        }
        
        // 주입받은 ApplicationContext 사용
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }
        
        String mapperBeanName = Character.toLowerCase(typeId.charAt(0)) + typeId.substring(1) + "Mapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);
        
        log.debug("매퍼 빈: {}", mapperBeanName);
        
        // 매퍼의 updateByPrimaryKey 메서드 찾기
        Method[] methods = mapper.getClass().getMethods();
        Method targetMethod = null;
        for (Method method : methods) {
            if ("updateByPrimaryKey".equals(method.getName())) {
                targetMethod = method;
                break;
            }
        }
        
        if (targetMethod == null) {
            throw new IllegalStateException(mapperBeanName + "에서 updateByPrimaryKey 메소드를 찾을 수 없습니다.");
        }
        
        // 매퍼 메서드 호출
        Object result = targetMethod.invoke(mapper, requestModel);
        return result;
    }

    
    
    @Override
    @SuppressWarnings("unchecked")
    public Object delete(Object requestModel) throws Exception {
        String typeId = "";
        Map<String, Object> paramMap = new HashMap<>();
        
        // requestModel에서 모든 필드를 paramMap으로 복사
        for (Field field : requestModel.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            Object value = field.get(requestModel);
            if (value != null) {
                paramMap.put(field.getName(), value);
            }
        }
        
        // typeId 추출
        try {
            typeId = (String) requestModel.getClass().getMethod("getTypeId").invoke(requestModel);
        } catch (Exception e) {
            log.debug("typeId 추출 실패: {}", e.getMessage());
        }
        
        log.debug("삭제 파라미터: typeId={}, requestModel={}, paramMap={}", typeId, requestModel.getClass().getSimpleName(), paramMap);
        
        if (typeId == null || typeId.isEmpty()) {
            throw new IllegalArgumentException("typeId가 비어있습니다.");
        }
        
        // 주입받은 ApplicationContext 사용
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }
        
        String[] splitTypeId = StringUtils.split(typeId, ":");
		typeId = Arrays.stream(splitTypeId).skip(1).findFirst().orElse(typeId);
        String mapperBeanName = Character.toLowerCase(typeId.charAt(0)) + typeId.substring(1) + "Mapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);
        
        log.debug("매퍼 빈: {}", mapperBeanName);
        
        // 매퍼의 deleteByPrimaryKey 메서드 찾기
        Method[] methods = mapper.getClass().getMethods();
        Method targetMethod = null;
        for (Method method : methods) {
            if ("deleteByPrimaryKey".equals(method.getName())) {
                targetMethod = method;
                break;
            }
        }
        
        if (targetMethod == null) {
            throw new IllegalStateException(mapperBeanName + "에서 deleteByPrimaryKey 메소드를 찾을 수 없습니다.");
        }
        
        /*
        // 파라미터 타입과 개수 확인 및 값 준비
        Class<?>[] parameterTypes = targetMethod.getParameterTypes();
        Parameter[] parameters = targetMethod.getParameters();
        Object[] args;
        
        log.debug("매퍼 메서드 파라미터 정보: 파라미터 개수={}", parameters.length);
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            log.debug("파라미터[{}]: name={}, type={}", i, param.getName(), param.getType().getSimpleName());
        }
        
        if (parameterTypes.length == 1) {
            // 단일 매개변수 (Model 객체 또는 기본 타입)
            log.debug("단일 매개변수 모드로 처리");
            
            // 파라미터 타입 확인
            Class<?> paramType = parameterTypes[0];
            String paramName = parameters[0].isNamePresent() ? parameters[0].getName() : "idn"; // 기본 키 필드명

            // Model 객체가 아닌 기본 타입(Integer, String 등)인 경우
            if (paramType.isPrimitive() || paramType == Integer.class || paramType == String.class || paramType == Long.class) {
                Object key_value = paramMap.get(paramName);
                if (key_value == null) {
                	key_value = paramMap.get("idn");
                }
                if (key_value == null) {
                	key_value = paramMap.get("mngt");
                }
                
                if (key_value == null) {
                    throw new IllegalArgumentException(String.format("단일 파라미터 '%s'의 값을 찾을 수 없습니다.", paramName));
                }
                args = new Object[]{key_value};
            } else {
                // Model 객체인 경우 그대로 전달
                args = new Object[]{requestModel};
            }
        } else {
            // 다중 매개변수 (@Param 어노테이션을 통한 개별 매개변수들)
            log.debug("다중 매개변수 모드로 처리");
            args = new Object[parameterTypes.length];
            for (int i = 0; i < parameters.length; i++) {
                Parameter param = parameters[i];
                String paramName = null;
                
                // @Param 어노테이션에서 파라미터명 추출 (우선순위 1)
                org.apache.ibatis.annotations.Param paramAnnotation = param.getAnnotation(org.apache.ibatis.annotations.Param.class);
                if (paramAnnotation != null) {
                    paramName = paramAnnotation.value();
                    log.debug("파라미터[{}]: @Param 어노테이션에서 파라미터명 추출 = {}", i, paramName);
                } else {
                    // @Param 어노테이션이 없는 경우 파라미터명 사용 (우선순위 2)
                    paramName = param.getName();
                    log.debug("파라미터[{}]: 파라미터명 사용 = {}", i, paramName);
                    
                    // arg0, arg1 등의 기본 파라미터명인 경우 대안 로직 시도
                    if (paramName.startsWith("arg")) {
                        log.debug("파라미터[{}]: 기본 파라미터명 감지, 대안 로직 시도", i);
                        // 파라미터 순서에 따른 키 필드 매핑 (순서 중요)
                        String[] commonKeyFields = {"mngt", "idn", "gid", "globalid"};
                        
                        // 파라미터 인덱스에 따라 순서대로 매핑
                        if (i < commonKeyFields.length) {
                            paramName = commonKeyFields[i];
                            log.debug("파라미터[{}]: 인덱스 기반 키 필드 매핑 = {}", i, paramName);
                        } else {
                            // 인덱스가 범위를 벗어나면 사용 가능한 첫 번째 키 필드 사용
                            for (String keyField : commonKeyFields) {
                                if (paramMap.containsKey(keyField)) {
                                    paramName = keyField;
                                    log.debug("파라미터[{}]: 범위 초과 키 필드 매핑 = {}", i, paramName);
                                    break;
                                }
                            }
                        }
                    }
                }
                
                // model 객체에서 해당 필드값 추출
                Object paramValue = null;
                try {
                    Field field = requestModel.getClass().getDeclaredField(paramName);
                    field.setAccessible(true);
                    paramValue = field.get(requestModel);
                    log.debug("파라미터[{}]: 필드에서 값 추출 성공 = {} = {}", i, paramName, paramValue);
                } catch (NoSuchFieldException e) {
                    // model에 필드가 없으면 paramMap에서 찾기
                    paramValue = paramMap.get(paramName);
                    log.debug("파라미터[{}]: paramMap에서 값 추출 = {} = {}", i, paramName, paramValue);
                }
                
                args[i] = paramValue;
                
                if (args[i] == null) {
                    log.error("파라미터[{}]: 필수 파라미터 '{}'의 값을 찾을 수 없습니다. 사용 가능한 필드: {}", 
                             i, paramName, paramMap.keySet());
                    throw new IllegalArgumentException(String.format("필수 파라미터 '%s'의 값을 찾을 수 없습니다. 사용 가능한 필드: %s", 
                                                                    paramName, paramMap.keySet()));
                }
            }
        }
        */
        
        // 매퍼 메서드 호출
        try {
            log.debug("매퍼 메서드 호출: {}.deleteByPrimaryKey()", mapperBeanName);
            //Object result = targetMethod.invoke(mapper, args);
            Integer gid = (Integer) paramMap.get("gid");
            Object result = targetMethod.invoke(mapper, new Object[]{gid});
            log.debug("매퍼 메서드 호출 완료: 결과 타입 = {}", result != null ? result.getClass().getSimpleName() : "null");
            return result;
        } catch (Exception e) {
            log.error("매퍼 메서드 호출 중 오류 발생: {}", e.getMessage(), e);
            throw new Exception("매퍼 메서드 호출 중 오류 발생: " + e.getMessage(), e);
        }
    }
    
    @Override
    public List<?> selectDetailTabList(String tabId, Map<String, Object> params) throws Exception {
        if (tabId == null || tabId.isEmpty()) {
            throw new IllegalArgumentException("tabId가 비어있습니다.");
        }
        if (applicationContextProvider == null) {
            throw new IllegalStateException("ApplicationContext가 주입되지 않았습니다.");
        }

        String [] splitTabId = StringUtils.split(tabId, ":");
        tabId = Arrays.stream(splitTabId).skip(1).findFirst().orElse(tabId);
        // 탭 ID 기반 리스트 매퍼 빈명: lowerCamel(tabId)+"ListMapper"
        String mapperBeanName = Character.toLowerCase(tabId.charAt(0)) + tabId.substring(1) + "ListMapper";
        Object mapper = applicationContextProvider.getBean(mapperBeanName, Object.class);

        // 메서드 선택: selectList
        java.lang.reflect.Method[] methods = mapper.getClass().getMethods();
        java.lang.reflect.Method targetMethod = null;
        for (java.lang.reflect.Method method : methods) {
            if ("selectList".equals(method.getName())) {
                targetMethod = method; break;
            }
        }
        if (targetMethod == null)
        {
            throw new IllegalStateException(mapperBeanName + "에서 selectList 메소드를 찾을 수 없습니다.");
        }
        if(params.isEmpty())
        {
        	throw new IllegalStateException(mapperBeanName + "에서 parmaeter를 찾을 수 없습니다.");
        }
        Object result = targetMethod.invoke(mapper, params);
        return (List<?>) result;
    }

}


