package com.its.pis.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.its.app.utils.ItsUtils;
import com.its.pis.entity.TbPisInfr;
import com.its.pis.process.DbmsData;
import com.its.pis.websocket.common.SubscribeIdentifier;
import com.its.pis.websocket.common.SubscribeRequest;
import com.its.pis.websocket.common.SubscribeResponseAccept;
import com.its.pis.websocket.message.c2f.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.File;
import java.util.Base64;

@Slf4j
@Controller
@RequestMapping(PisWebSocketConfig.WS_C2C_ENDPOINT)
public class PisWebSocketHandlerC2C extends PisWebSocketHandler {

    public PisWebSocketHandlerC2C() {
        super("C2C");
        log.info("PisWebSocketHandlerC2C() START");
    }
    public PisWebSocketHandlerC2C(String type) {
        super(type);
        log.info("PisWebSocketHandlerC2C() START");
    }

    //클라이언트가 웹소켓 서버로 메시지를 전송했을 때 실행
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        String payloadMessage = message.getPayload();
        if (payloadMessage == null || payloadMessage.trim().isEmpty()) {
            log.error("C2C: Payload data is empty");
            return;
        }
        log.info("C2C: Payload, RX] {}", payloadMessage);
        if (payloadMessage.contains("CONNECT")) {
            return;
        }

        PisWebSocketSession sessionClient = PisWebSocketSessionManager.getInstance().getSession(session);
        if (sessionClient == null) {
            log.error("C2C: Request session not found, session will be closed {}", session);
            session.close();
            return;
        }

        TbPisInfr pis = sessionClient.getObj();
        if (pis == null) {
            log.error("C2C: PIS object not found, session will be closed {}", session);
            session.close();
            return;
        }

        C2FMessage<C2FMessagePayload> c2fMessage = this.mapper.readValue(payloadMessage, new TypeReference<C2FMessage<C2FMessagePayload>>(){});
        if (c2fMessage.getCommand() == null) {
            log.error("C2C: C2FMessage, {}", c2fMessage);
            // C2C 클라이언트인 경우 처리...
            SubscribeResponseAccept response = this.mapper.readValue(payloadMessage, SubscribeResponseAccept.class);
            if (response != null) {
                log.info("C2C: SubscribeResponseAccept, {}", response);
                pis.channelLogin(pis.getSession());
                return;
            }
            log.error("C2C: command data not found, session will be closed {}", session);
            session.close();
            return;
        }
        if (C2FConstants.subscribe.equals(c2fMessage.getCommand())) {
            log.info("C2C: RX] subscribe");
            try {
                SubscribeRequest subscribe = this.mapper.readValue(payloadMessage, SubscribeRequest.class);
                log.info("RX] {}", this.mapper.writeValueAsString(subscribe));
                pis.channelLogin(pis.getSession());

                SubscribeResponseAccept response = SubscribeResponseAccept.builder()
                        .identifier(SubscribeIdentifier.builder()
                                .channel("ParkingLotChannel").build())
                        .essntl_info("Not Setting Info")
                        .type("confirm_subscription")
                        .build();
                String strMessage = this.mapper.writeValueAsString(response);
                sessionClient.sendMessage(response.getType(), new TextMessage(strMessage));
                log.info("TX] {}", strMessage);
            } catch (JsonProcessingException e) {
                log.error("TX] Exception: {}", e.getMessage());
                session.close();
            }
            return;
        }

        try {
            String eventName = c2fMessage.getData().getPayload().getEvent_name();
            if (C2FConstants.prk_plce_sttus_info.equals(eventName)) {
                C2FMessage<PrkPlceSttusInfo> sttusInfo = this.mapper.readValue(payloadMessage, new TypeReference<C2FMessage<PrkPlceSttusInfo>>(){});
                C2FMessage<PrkPlceSttusInfo> sttusTemp = sttusInfo;
                sttusTemp.getData().getPayload().getPrk_place_image().setPrk_plce_image_data("base64 image data string");
                log.info("C2C: RX] prk_plce_sttus_info");
                log.info("RX] {}", this.mapper.writeValueAsString(sttusTemp));

                if (sttusInfo.getData().getPayload().getPrk_place_image() != null) {
                    int imageType = sttusInfo.getData().getPayload().getPrk_place_image().getPrk_plce_image_type();
                    String imageStringData = sttusInfo.getData().getPayload().getPrk_place_image().getPrk_plce_image_data();
                    byte[] decodedBytes = Base64.getDecoder().decode(imageStringData);
                    String saveDir = ItsUtils.createUserDir("/images/");
                    String outputFileName = saveDir + sttusInfo.getData().getPayload().getPrk_plce_manage_no();
                    switch(imageType) {
                        case 0: outputFileName += ".bmp"; break;
                        case 1: outputFileName += ".gif"; break;
                        case 2: outputFileName += ".jpg"; break;
                        case 3: outputFileName += ".png"; break;
                        default: outputFileName += ""; break;
                    }

                    FileUtils.writeByteArrayToFile(new File(outputFileName), decodedBytes);
                }
//                byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
//                FileUtils.writeByteArrayToFile(new File(outputFileName), decodedBytes);
//                byte[] fileContent = FileUtils.readFileToByteArray(new File(filePath));
//                String encodedString = Base64.getEncoder().encodeToString(fileContent);

            } else if (C2FConstants.prk_plce_opr_info.equals(eventName)) {
                C2FMessage<PrkPlceOprInfo> oprInfo = this.mapper.readValue(payloadMessage, new TypeReference<C2FMessage<PrkPlceOprInfo>>(){});
                log.info("C2C: RX] prk_plce_opr_info");
                log.info("RX] {}", this.mapper.writeValueAsString(oprInfo));
            } else if (C2FConstants.prk_plce_rl_time_info.equals(eventName) || C2FConstants.prk_plce_rl_time_info_cycle.equals(eventName)) {
                C2FMessage<PrkPlceRlTimeResponseInfo> rlTimeInfo = this.mapper.readValue(payloadMessage, new TypeReference<C2FMessage<PrkPlceRlTimeResponseInfo>>(){});
                pis.setRlTimeInfo(rlTimeInfo);
                dbmsDataProcess.add(new DbmsData(DbmsData.DBMS_DATA_RL_TIME, false, rlTimeInfo, pis));
                log.info("C2C: RX] prk_plce_rl_time_info");
                log.info("RX] {}", this.mapper.writeValueAsString(rlTimeInfo));
            } else if (C2FConstants.prk_plce_reservation_response_info.equals(eventName)) {
                C2FMessage<PrkPlceReservationResponseInfo> reservationInfo = this.mapper.readValue(payloadMessage, new TypeReference<C2FMessage<PrkPlceReservationResponseInfo>>(){});
                log.info("C2C: RX] prk_plce_reservation_response_info");
                log.info("RX] {}", this.mapper.writeValueAsString(reservationInfo));
            } else if (C2FConstants.prk_plce_vhcl_location_response_info.equals(eventName)) {
                C2FMessage<PrkPlceVhclLocationResponseInfo> locationInfo = this.mapper.readValue(payloadMessage, new TypeReference<C2FMessage<PrkPlceVhclLocationResponseInfo>>(){});
                log.info("C2C: RX] prk_plce_vhcl_location_response_info");
                log.info("RX] {}", this.mapper.writeValueAsString(locationInfo));
            } else {
                log.error("C2C: RX] Unknown event name, {}", eventName);
                log.error("RX] Payload, {}", payloadMessage);
            }
        } catch(NullPointerException e) {
            log.error("C2C: RX] NullPointerException, Payload data null, {}", payloadMessage);
        }
    }

}
