package com.eactive.eai.rms.onl.apim.approval.user;

import com.eactive.apim.portal.approval.entity.Approval;
import com.eactive.apim.portal.approval.service.ApprovalDeployException;
import com.eactive.apim.portal.approval.statemachine.listener.ApprovalListener;
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.ApprovalStatus;
import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums.OrgStatus;
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
import com.eactive.apim.portal.template.entity.MessageCode;
import com.eactive.apim.portal.template.service.MessageRecipient;
import com.eactive.apim.portal.template.service.MessageSendService;
import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgService;
import com.eactive.eai.rms.data.entity.onl.apim.portaluser.PortalUserService;
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUI;
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUIMapper;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

@Service
@Transactional
@RequiredArgsConstructor
public class PortalUserApprovalListener implements ApprovalListener {

    private static final Logger logger = LoggerFactory.getLogger(PortalUserApprovalListener.class);
    private static final String PORTAL_PROPERTY_GROUP = "Portal";
    private final PortalPropertyService portalPropertyService;
    private final PortalOrgService portalOrgService;
    private final PortalUserService portalUserService;
    private final MessageSendService messageSendService;
    private final PortalOrgUIMapper portalOrgUIMapper;

    public static RestTemplate createRestTemplateWithTimeout(int connectTimeout) {

        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(connectTimeout)
            .setConnectTimeout(connectTimeout)
            .setSocketTimeout(connectTimeout)
            .build();

        HttpClient httpClient =
            HttpClientBuilder.create()
                .setMaxConnTotal(50)
                .setMaxConnPerRoute(20)
                .setDefaultRequestConfig(requestConfig)
                .build();

        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setRequestFactory(factory);

        return restTemplate;
    }

    @Override
    public void execute(Approval approval, Map<String, Object> options) throws ApprovalDeployException {
        logger.info("Approval {} ended successfully", approval.getId());

        String userId = approval.getTargetId();

        PortalUser portalUser = portalUserService.findByUserId(userId);
        portalUser.setApprovalStatus(PortalUserEnums.ApprovalStatus.COMPLETED);
        portalUserService.save(portalUser);

        PortalOrg portalOrg = portalUser.getPortalOrg();
        portalOrg.setApprovalStatus(ApprovalStatus.COMPLETED);
        portalOrg.setOrgStatus(OrgStatus.ACTIVE);
        portalOrgService.save(portalOrg);

        // syncStaging(portalOrgUIMapper.toVo(portalOrg));
        sendApprovalResult(portalUser);
    }

    private void sendApprovalResult(PortalUser portalUser) {
        MessageRecipient recipient = new MessageRecipient();
        recipient.setUsername(portalUser.getUserName());
        recipient.setPhone(portalUser.getMobileNumber());
        recipient.setUserId(portalUser.getEmailAddr());
        Map<String, String> params = new HashMap<>();
        // DB 템플릿 MANAGER_WITH_ORG_REGISTER_APPROVED SMS 변수(%ORG_NAME%)에 매핑
        PortalOrg org = portalUser.getPortalOrg();
        if (org != null) {
            params.put("ORG_NAME", org.getOrgName());
        }
        messageSendService.sendMessage(MessageCode.MANAGER_WITH_ORG_REGISTER_APPROVED, recipient, params);
    }

    /**
     * @deprecated 광주은행에서는 사용하지 않음. (개발/운영 완전 분리)
     * @param portalOrgUI
     * @throws ApprovalDeployException
     */
    private void syncStaging(PortalOrgUI portalOrgUI) throws ApprovalDeployException {
    		throw new RuntimeException("Unable use this method(syncStaging())");
    		
//        // 프록시를 통한 스테이징 서버 호출 추가
//        Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
//        String apiKey = properties.get("apiKey");
//        String proxyUrl = properties.get("portal.url");
//        String timeout = properties.getOrDefault("deploy.proxy_timeout", "10000");
//        String proxyEndpoint = proxyUrl + "/_onl/apim/portalorg/portalOrgMan.json";
//
//        HttpHeaders headers = new HttpHeaders();
//        headers.setContentType(MediaType.APPLICATION_JSON);
//        headers.set("X-API-KEY", apiKey);
//        headers.set("target_host", "stg");
//        headers.set("action", "insert");
//
//        portalOrgUI.setCompRegFile(null);
//        HttpEntity<PortalOrgUI> request = new HttpEntity<>(portalOrgUI, headers);
//
//        try {
//            ResponseEntity<String> response = createRestTemplateWithTimeout(Integer.parseInt(timeout)).exchange(
//                proxyEndpoint,
//                HttpMethod.POST,
//                request,
//                String.class
//            );
//
//            if (!response.getStatusCode().is2xxSuccessful()) {
//                logger.error("Failed to sync with staging server. Status: {}, Body: {}", response.getStatusCode(), response.getBody());
//                throw new ApprovalDeployException("기관 정보 배포에 실패 했습니다.");
//            }
//        } catch (Exception e) {
//            logger.error("Failed to sync with staging server. {}", e.getMessage());
//            throw new ApprovalDeployException("기관 정보 배포에 실패 했습니다.");
//        }
    }

    @Override
    public void rollback(Approval approval) {
        logger.debug("Rollback started for approval ID: {}, type: {}, status: {}",
            approval.getId(),
            approval.getApprovalType(),
            approval.getApprovalStatus());
        logger.info("Approval {} rollback", approval.getId());
        String userId = approval.getTargetId();

        PortalUser portalUser = portalUserService.findByUserId(userId);
        PortalOrg portalOrg = portalUser.getPortalOrg();

        // 거절 통지에 필요한 정보를 반려 처리(정보 마스킹) 이전에 캡처
        String noticeName = portalUser.getUserName();
        String noticePhone = portalUser.getMobileNumber();
        String noticeEmail = portalUser.getEmailAddr();
        String noticeOrgName = portalOrg != null ? portalOrg.getOrgName() : null;
        String rejectReason = extractRejectReason(approval);

        // 개인→법인 전환 요청 반려: approvalStatus가 PENDING이면 전환 신청이었으므로 개인 사용자로 복원
        if (PortalUserEnums.ApprovalStatus.PENDING.equals(portalUser.getApprovalStatus())) {
            logger.info("Approval {} is a personal-to-corporate conversion rejection. Reverting user {} to personal user.", approval.getId(), userId);
            portalUser.setRoleCode(PortalUserEnums.RoleCode.ROLE_USER);
            portalUser.setUserStatus(PortalUserEnums.UserStatus.ACTIVE);
            portalUser.setApprovalStatus(PortalUserEnums.ApprovalStatus.COMPLETED);
            portalUser.setPortalOrg(null);
        } else {
            // 신규 법인 사용자 등록 반려: 반려된 사용자로 처리
            LocalDateTime now = LocalDateTime.now();
            String rejectedDate = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));

            portalUser.setUserName("반려된 사용자");
            portalUser.setMobileNumber("");
            portalUser.setLoginId(portalUser.getId() + "-d" + rejectedDate);
            portalUser.setEmailAddr(portalUser.getId() + "-d" + rejectedDate);
            portalUser.setUserStatus(PortalUserEnums.UserStatus.INACTIVE);
            portalUser.setApprovalStatus(PortalUserEnums.ApprovalStatus.REJECTED);
            portalUser.setPhoneNumber(null);
            portalUser.setAuthCompletedYn("N");
            portalUser.setLoginFailureCount(0);
            portalUser.setAccountLockYn("N");
        }

        portalUserService.save(portalUser);

        if (portalOrg != null) {
            portalOrg.setOrgName("삭제된법인");
            portalOrg.setApprovalStatus(ApprovalStatus.REJECTED);
            portalOrg.setOrgStatus(OrgStatus.REMOVED);
            portalOrg.clearSensitiveDataOnRemoval();

            portalOrgService.save(portalOrg);
        }

        // 법인관리자/법인 등록 거절 통지 (정보 마스킹 이전 캡처값 사용)
        MessageRecipient recipient = new MessageRecipient();
        recipient.setUsername(noticeName);
        recipient.setPhone(noticePhone);
        recipient.setUserId(noticeEmail);
        Map<String, String> params = new HashMap<>();
        // DB 템플릿 MANAGER_WITH_ORG_REGISTER_REJECTED SMS 변수(%ORG_NAME%, %REASON%)에 매핑
        if (noticeOrgName != null) {
            params.put("ORG_NAME", noticeOrgName);
        }
        params.put("REASON", rejectReason);
        messageSendService.sendMessage(MessageCode.MANAGER_WITH_ORG_REGISTER_REJECTED, recipient, params);
    }

    private String extractRejectReason(Approval approval) {
        if (approval.getApprovers() == null) {
            return "";
        }
        return approval.getApprovers().stream()
            .map(com.eactive.apim.portal.approval.entity.Approver::getApprovalMessage)
            .filter(m -> m != null && !m.isEmpty())
            .findFirst().orElse("");
    }
}
