package incheon.uis.ums.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import incheon.com.cmm.context.RequestContext;
import incheon.com.cmm.service.ResultVO;
import incheon.uis.ums.file.dto.AttachUploadRequestDTO;
import incheon.uis.ums.file.mapper.PreAttachDetailMapper;
import incheon.uis.ums.file.service.CmtFileService;
import incheon.uis.ums.file.vo.CmtFileVO;
import incheon.uis.ums.file.vo.KeyMappingVO;
import incheon.uis.ums.file.vo.PreAttachDetailVO;
import incheon.uis.ums.service.DynamicModelService;
import incheon.uis.ums.service.UisAttachFileService;
import incheon.uis.ums.service.UisFacilityService;
import incheon.uis.ums.util.UisDynamicFieldUtils;
import incheon.uis.ums.util.UisFileUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
@RequiredArgsConstructor
public class UisAttachFileServiceImpl implements UisAttachFileService{

    private final DynamicModelService dynamicModelService;
    private final UisFacilityService uisFacilityService;
    private final UisFileUtils uisFileUtils;
    private final CmtFileService cmtFileService;
    private final UisDynamicFieldUtils dynamicFieldUtils;
    private final PreAttachDetailMapper preAttachDetailMapper;
    // attachFile에 업로드 가능한 형식
    private final List<String> ALLOWED_EXTENSIONS = Arrays.asList(
        "jpeg", "png", "bmp", "gif", "tif", "jpg", "pdf", "7z", "zip",
        "xls", "xlsm", "xlsx", "ppt", "pptx", "hwp", "hwpx", "doc",
        "xml", "mxd", "dwg", "dxf", "txt", "mp4"
    );

    @Override
    @Transactional
    public ResultVO saveFileandAttach(MultipartFile file, AttachUploadRequestDTO attachAttr, HttpServletRequest request) {
        ResultVO resultVO = new ResultVO();
        Object requestModel = null;
        try {
            final String entity = attachAttr.getEntity();
            final String typeId = dynamicFieldUtils.strTypeIdToCamel(entity);
            final String originalFilename = file.getOriginalFilename();
            final String extension = uisFileUtils.getFileExtension(originalFilename);

            // 파일 형식 확인
            if(!ALLOWED_EXTENSIONS.contains(extension)) {
                log.error("UisAttachFileServiceImpl 파일 업로드 실패: 지원하지 않는 파일 형식입니다. fileName={}", file.getOriginalFilename());
                throw new IllegalArgumentException(file.getOriginalFilename() + " 파일은 지원하지 않는 파일 형식입니다.");
            }

            //1. 파일 업로드
            CmtFileVO fileVO = uisFileUtils.saveUploadedFile(file, entity, request);
            //2. cmt_file_d 저장
            cmtFileService.insertFile(fileVO);

            //3.파일 내역 선행 등록 있는 경우---------------------------------------
            if(!"".equals(attachAttr.getMainEntity())) {
            	//공통VO로 세팅
                PreAttachDetailVO preAttachDetailVO = (PreAttachDetailVO) getPreAttachDetailVO(file.getOriginalFilename(), attachAttr);
                switch(attachAttr.getMainEntity()) {
                  case "cmt_cnfl_d" : preAttachDetailMapper.insertCnflD(preAttachDetailVO); break;
                  case "grt_plan_d" : preAttachDetailMapper.insertGrtPlanD(preAttachDetailVO); break;
                }

                //__attach insert 시 필요한 값 매핑 List에 세팅
                List<KeyMappingVO> keyMappingList = attachAttr.getKeyMapping();
                for(KeyMappingVO keyMapping : keyMappingList) {
                   switch(keyMapping.getMain()){
                     case "idn": keyMapping.setValue(preAttachDetailVO.getIdn()); break;
                     case "mngt": keyMapping.setValue(preAttachDetailVO.getMngt()); break;
                     case "seq": keyMapping.setValue(preAttachDetailVO.getSeq()); break;
                     case "ftc": keyMapping.setValue(preAttachDetailVO.getFtc()); break;
                   }
                }
                requestModel = getAttachModel(file, typeId, fileVO.getFileSeq(), keyMappingList);
            }else {
                //4.파일 내역 선행 등록 없는 경우
                requestModel = getAttachModel(file, typeId, fileVO.getFileSeq(), attachAttr.getMainFieldMapping());
            }

            //5. __attach 저장
            Object inputResult = insert(requestModel);

            resultVO.setResultCode(0);
            resultVO.setResultMessage("파일이 성공적으로 업로드 되었습니다.");

        } catch (IOException e) {
            log.error("파일 업로드 실패: fileName={}", file.getOriginalFilename(), e);
            resultVO.setResultCode(-1);
            resultVO.setResultMessage("파일 업로드 실패:" + file.getOriginalFilename());
        } catch (IllegalArgumentException e) {
            log.error("파일 업로드 실패: fileName={}", file.getOriginalFilename(), e);
            resultVO.setResultCode(-1);
            resultVO.setResultMessage(e.getMessage());
        } catch (Exception e) {
            log.error("파일 업로드 실패: fileName={}", file.getOriginalFilename(), e);
            resultVO.setResultCode(-1);
            resultVO.setResultMessage("파일 업로드 실패:" + file.getOriginalFilename());
        }
    	return resultVO;
    }

    //파일내역 공통VO
    private Object getPreAttachDetailVO(String fileName, AttachUploadRequestDTO request) {
        //공통필드세팅
        PreAttachDetailVO preAttachDetailVO = new PreAttachDetailVO();
        preAttachDetailVO.setNam(fileName);
        preAttachDetailVO.setFrstRegId(RequestContext.getCurrentUserId());
        preAttachDetailVO.setLastMdfcnId(RequestContext.getCurrentUserId());
        preAttachDetailVO.setUseYn("Y");

        //key mapping List에 있는 값들 동적 매핑
        List<KeyMappingVO> keyMapping = request.getMainFieldMapping();
        for (KeyMappingVO vo : keyMapping) {
            String fieldName = vo.getAttach() != null ? vo.getAttach() : vo.getMain();
            Object value = vo.getValue();
            if (StringUtils.isNotBlank(fieldName)) {
                dynamicFieldUtils.setField(preAttachDetailVO, dynamicFieldUtils.snakeToCamel(fieldName), value);
            }
        }
    	
        return preAttachDetailVO;
    }

    //attachModel 세팅
    private Object getAttachModel(MultipartFile file, String typeId, BigDecimal fileSeq, List<KeyMappingVO> keyMapping) {
        Object requestModel = dynamicModelService.getModelInstance(typeId);
        dynamicFieldUtils.setField(requestModel, "attName", file.getOriginalFilename()); //파일명 
        dynamicFieldUtils.setField(requestModel, "contentType", uisFileUtils.getContentType(file.getOriginalFilename())); //컨텐츠 타입
        dynamicFieldUtils.setField(requestModel, "dataSize", file.getSize()); //데이터사이즈
        dynamicFieldUtils.setField(requestModel, "fileSeq", fileSeq);
        dynamicFieldUtils.setField(requestModel, "lastMdfcnId", RequestContext.getCurrentUserId());
        dynamicFieldUtils.setField(requestModel, "frstRegId", RequestContext.getCurrentUserId());
        dynamicFieldUtils.setField(requestModel, "typeId", typeId);

        //key mapping List에 있는 값들 동적 매핑
        for (KeyMappingVO vo : keyMapping) {
            String fieldName = vo.getAttach() != null ? vo.getAttach() : vo.getMain();
            Object value = vo.getValue();
            if (StringUtils.isNotBlank(fieldName)) {
            	dynamicFieldUtils.setField(requestModel, dynamicFieldUtils.snakeToCamel(fieldName), value);
            }
        }
        return requestModel;
    }

    //insert
    private Object insert(Object requestModel) {
        try {
            return uisFacilityService.insert(requestModel);

        } catch (Exception e) {
            log.error("시설 정보 insert 실패. requestModel={}", requestModel, e);
            throw new IllegalStateException("시설 정보 저장에 실패했습니다.", e);
        }
    }


}
