package com.eactive.eai.rms.onl.common.service.ums;

import com.eactive.apim.portal.common.util.PhoneNumberUtil;
import com.eactive.apim.portal.template.entity.MessageRequest;
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
import com.eactive.eai.transformer.util.ByteUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;

@Slf4j
@Component
public class StandardMessageFactory {

    private final StandardMessageTemplate template;

    private final MonitoringPropertyService monitoringPropertyService;

    public StandardMessageFactory(MonitoringPropertyService monitoringPropertyService) {
        this.monitoringPropertyService = monitoringPropertyService;
        this.template = new StandardMessageTemplate();
    }

    private static final String TYPE_EMAIL = "EMAIL";
    private static final String TYPE_KAKAO = "KAKAO";

    public String createMessage(MessageRequest request) {
        if (request.getMessageType() == null) {
            throw new IllegalStateException("Message type is required. Request ID: " + request.getId());
        }

        String messageType = request.getMessageType().toUpperCase();
        log.debug("Creating {} type message for request ID: {}", messageType, request.getId());

        Map<String, FieldDefinition> messageTemplate = template.getCompleteTemplate(messageType);

        // 기본 필드들 설정
        setCommonFields(messageTemplate, request);

        switch (messageType) {

            case TYPE_EMAIL:
                if (request.getEmail() == null || request.getEmail().trim().isEmpty()) {
                    throw new IllegalStateException("Email is required for EMAIL type message. Request ID: " + request.getId());
                }
                setEmailFields(messageTemplate, request);
                break;

            case TYPE_KAKAO:
                if (request.getPhone() == null || request.getPhone().trim().isEmpty()) {
                    throw new IllegalStateException("Phone number is required for KAKAO type message. Request ID: " + request.getId());
                }
                setKakaoFields(messageTemplate, request);
                break;

            default:
                throw new IllegalStateException("Unsupported message type: " + messageType + " for request ID: " + request.getId());
        }

        // Calculate lengths before building the final message
        calculateAndSetMessageLengths(messageTemplate);

        String message = buildMessage(messageTemplate);
        if (log.isDebugEnabled()) {
            StringBuilder templateDebug = new StringBuilder("\n");
            messageTemplate.forEach((key, field) -> {
                templateDebug.append(String.format("\n%-35s | length: %-4d | value: '%s'",
                        key, field.getLength(), field.getValue()));
            });

            log.debug("Message details for request ID: {}\nUMS Message Template Structure:{}\n\nFinal assembled message:\n{}",
                    request.getId(),
                    templateDebug,
                    message);
        }

        return message;
    }

    private void setCommonFields(Map<String, FieldDefinition> template, MessageRequest request) {
        String systemMode = System.getProperty("eai.systemmode");
        LocalDateTime now = LocalDateTime.now();
        String currentDateTime = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String currentDate = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String currentTime = now.format(DateTimeFormatter.ofPattern("HHmmss"));
        String requestNumber = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"))
                + RandomStringUtils.random(13, true, true);

        // 표준 헤더 설정
        template.get("tlgrWrtnDt").setValue(currentDateTime);
        template.get("eaiIntfId").setValue(request.getEaiInterfaceId());
        template.get("exctnModeDscd").setValue(systemMode);

        // UMS 헤더 설정
        template.get("CRTN_DT").setValue(currentDate);
        template.get("CRTN_TM").setValue(currentTime);
        template.get("ACPN_DT").setValue(currentDate);
        template.get("ACPN_DRTM").setValue(currentTime);
        template.get("SVC_ID").setValue(request.getServiceId());
        template.get("RQST_TMSG_NO").setValue(requestNumber);
    }

    private void setEmailFields(Map<String, FieldDefinition> template, MessageRequest request) {
        template.get("UMS_MSG_DV_CD").setValue("E");
        template.get("SNDR_NM").setValue("케이뱅크");
        template.get("SNDR_EMAIL_ADR").setValue("customer_center@kbanknow.com");
        template.get("RCV_EMAIL_ADR").setValue(request.getEmail());
        template.get("EMAIL_TTL").setValue(request.getSubject());
        String emailCtt = request.getMessage();
        int emailCttLen = emailCtt.getBytes(StandardCharsets.UTF_8).length;
        FieldDefinition emailCttField = new FieldDefinition(emailCttLen, emailCtt);
        template.put("EMAIL_CTT", emailCttField);
        template.get("DATPT_LEN").setValue(String.format("%08d", emailCttLen));
    }

    private void setKakaoFields(Map<String, FieldDefinition> template, MessageRequest request) {
        template.get("UMS_MSG_DV_CD").setValue("K");
        template.get("KKO_TMPLT_ID").setValue(request.getServiceId());
        template.get("KKO_CTT").setValue(request.getMessage());
        template.get("KKO_ATTACHMENT").setValue("{\"button\":[{\"name\":\"채널 추가\",\"type\":\"AC\"}]}");
        template.get("KKO_SMS_SND_MSG").setValue(request.getMessage());
        template.get("RCPN_MVBL_TEL_NO").setValue(PhoneNumberUtil.digitsOnly(request.getPhone()));

        String kkoSenderKey = monitoringPropertyService.getPrpty2ValById("Monitoring", "ums.kko.sender.key");
        template.put("KKO_SENDER_KEY", new FieldDefinition(40, kkoSenderKey));     // 카카오발신프로필키
    }

    private String buildMessage(Map<String, FieldDefinition> template) {
        StringBuilder message = new StringBuilder();
        template.forEach((key, field) ->
                message.append(padRight(field.getValue(), field.getLength())));
        return message.toString();
    }

    private String padRight(String str, int length) {
        if(StringUtils.isBlank(str)) {
            StringBuilder spaces = new StringBuilder();
            for (int i = 0; i < length; i++) {
                spaces.append(" ");
            }
            return spaces.toString();
        }
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);

        String padStr = new String(ByteUtil.paddingright(bytes, length, (byte)0x20), StandardCharsets.UTF_8);
        return padStr;
    }

    private void calculateAndSetMessageLengths(Map<String, FieldDefinition> template) {
        // Calculate TMSG_LEN (UMS message length)
        int umsLength = calculateUmsMessageLength(template);
        template.get("TMSG_LEN").setValue(String.format("%08d", umsLength));

        // Calculate tlgrLen (total message length)
        int totalLength = calculateTotalMessageLength(template);
        template.get("tlgrLen").setValue(String.format("%08d", totalLength));
    }

    private int calculateUmsMessageLength(Map<String, FieldDefinition> template) {
        // Start calculating from UMS header (STR_DV_CD부터)
        boolean startCounting = false;
        int length = 0;

        for (Map.Entry<String, FieldDefinition> entry : template.entrySet()) {
            // STR_DV_CD부터 계산 시작
            if (entry.getKey().equals("STR_DV_CD")) {
                startCounting = true;
            }

            if (startCounting) {
                length += entry.getValue().getLength();
            }
        }

        return length;
    }

    private int calculateTotalMessageLength(Map<String, FieldDefinition> template) {
        int length = 0;
        // tlgrLen 필드를 제외한 모든 필드의 길이를 합산
        for (Map.Entry<String, FieldDefinition> entry : template.entrySet()) {
            if (!entry.getKey().equals("tlgrLen")) {
                length += entry.getValue().getLength();
            }
        }
        return length;
    }
}
