package com.its.vms.xnettcp.vms.process;

import com.its.vms.domain.NET;
import com.its.vms.dto.TbVmsCtlrDto;
import com.its.vms.xnettcp.vms.protocol.impl.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@RequiredArgsConstructor
public class TcpServerSendDataProcess {

    private final TbVmsCtlrDto vmsObj;

    private final LinkedBlockingQueue<TcpServerSendData> reqCommandBlockingQueue = new LinkedBlockingQueue<>(100);
    private final ThreadPoolExecutor taskExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(1);

    public void run() {
        log.info("TcpServerReqDataProcess[{}].run: Start.", this.vmsObj.getVmsCtlrNmbr());
        this.taskExecutor.execute(() -> {
            boolean isRunning = true;
            while (isRunning) {
                try {
                    TcpServerSendData reqData = this.reqCommandBlockingQueue.take();
                    process(reqData);
                }
                catch (InterruptedException e) {
                    log.error("TcpServerReqDataProcess.Task: Exception: {}", e.getMessage(), e);
                    Thread.currentThread().interrupt();
                    isRunning = false;
                }
            }
        });
    }

    public void process(TcpServerSendData data) {

        MDC.put("id", this.vmsObj.getLogKey());

        boolean isConnected = (this.vmsObj.getNetState() > NET.CLOSED && this.vmsObj.getChannel() != null);
        boolean isRequested = false;
        if (data.elapsed() > 500) {
            log.info("TcpServerReqDataProcess.process: VMS {}, command({}), connected({}), Elapsed: {} ms.", this.vmsObj.getVmsCtlrNmbr(), data.getOpCode(), isConnected, data.elapsed());
        }

        boolean result = true;
        if (isConnected) {
            try {
                switch (data.getOpCode()) {
                    case OP_VMS_LOCAL_USER_COMMAND:
                        VmsReqLocalUserCommand reqLocalUserCommand = (VmsReqLocalUserCommand)data.getData();
                        if (reqLocalUserCommand.getCommand() == 0) {
                            result = vmsObj.downloadForm();
                        }
                        break;
                    case OP_VMS_STATUS_REQ:
                        VmsReqStatus reqStatus = new VmsReqStatus(this.vmsObj);
                        result = this.vmsObj.sendData(reqStatus, 1);
                        break;
                    case OP_VMS_POWER_MODULE_STATUS_REQ:
                        VmsReqPowerModuleStatus reqPowerModuleStatus = new VmsReqPowerModuleStatus(this.vmsObj);
                        result = this.vmsObj.sendData(reqPowerModuleStatus, 1);
                        break;
                    case OP_VMS_DISPLAY_MODULE_STATUS_REQ:
                        VmsReqDisplayModuleStatus reqDisplayModuleStatus = new VmsReqDisplayModuleStatus(this.vmsObj);
                        result = this.vmsObj.sendData(reqDisplayModuleStatus, 1);
                        break;
                    case OP_VMS_PARAMETER_REQ:
                        VmsReqParameter reqParameter = new VmsReqParameter(this.vmsObj);
                        result = this.vmsObj.sendData(reqParameter, 1);
                        break;
//                    case OP_VMS_DOWNLOAD_FORM_SCHEDULE:
//                        VmsJobDownloadScheduleFrom downloadScheduleFrom = new VmsJobDownloadScheduleFrom(this.vmsObj, (boolean) data.getData());
//                        result = downloadScheduleFrom.process();
//                        break;
                    case OP_VMS_STOP_IMAGE_REQ:
                        VmsReqStopImage reqStopImage = new VmsReqStopImage(this.vmsObj, (Integer)data.getData());
                        result = this.vmsObj.sendData(reqStopImage, 1);
                        break;
                    case OP_VMS_UPLOAD_CURRENT_DISPLAY_FORM:
                        VmsReqUploadCurrentDisplayForm reqUploadCurrentDisplayForm = new VmsReqUploadCurrentDisplayForm(this.vmsObj);
                        result = this.vmsObj.sendData(reqUploadCurrentDisplayForm, 1);
                        break;
                    case OP_VMS_DISPLAY_DEFAULT_FORM:
                        VmsReqDisplayDefaultForm reqDisplayDefaultForm = new VmsReqDisplayDefaultForm(this.vmsObj);
                        result = this.vmsObj.sendData(reqDisplayDefaultForm, 1);
                        break;
                    case OP_VMS_BLANK:
                        VmsReqBlank reqBlank = new VmsReqBlank(this.vmsObj);
                        result = this.vmsObj.sendData(reqBlank, 1);
                        break;
                    case OP_VMS_DISPLAY_FORM_ID:
                        VmsReqDisplayFromId reqDisplayFormId = new VmsReqDisplayFromId(this.vmsObj, (Integer)data.getData());
                        result = this.vmsObj.sendData(reqDisplayFormId, 1);
                        break;
                    case OP_VMS_UPLOAD_FORM_SCHEDULE:
                        VmsReqUploadFormSchedule reqUploadScheduleFrom = new VmsReqUploadFormSchedule(this.vmsObj);
                        result = this.vmsObj.sendData(reqUploadScheduleFrom, 1);
                        break;

                    case OP_VMS_DATA_DOWNLOAD:
                        if (data.getData() == null) {
                            this.vmsObj.downloadSymbLib();
                        }
                        break;
                    case OP_VMS_STATUS_CONTROL:
                        VmsReqStatusControl statusControl = (VmsReqStatusControl) data.getData();
                        result = this.vmsObj.sendData(statusControl, 1);
//                        byte[] command = control.getCommand();
//                        // TODO: 전송성공하면
//                        if (isRequested) {
//                            this.vmsObj.getModule().setOnOff(true);
//                            //this.vmsCtlr.getModule().setOnOff(command[0]);
//                        } else {
//                            int retry = this.vmsObj.getModule().getRetry();
//                            retry++;
//                            this.vmsObj.getModule().setRetry(retry);
//                            this.vmsObj.getModule().setOnOff(false);
//                        }
                        break;
                    default:
                        break;
                }
            } catch (Exception e) {
                log.error("TcpServerReqDataProcess.process: VMS {}, Exception: {}", this.vmsObj.getVmsCtlrNmbr(), e.toString());
            }
        }
        if (!result) {
            log.info("TcpServerReqDataProcess.process: VMS {}, request failed. command({}), connected({}), Requested({}).", this.vmsObj.getVmsCtlrNmbr(), data.getOpCode(), isConnected, isRequested);
        }
        //log.info("TcpServerReqDataProcess.process: VMS {}, command({}), connected({}), Requested({}).", this.vmsObj.getVmsCtlrNmbr(), data.getCommand(), isConnected, isRequested);

        MDC.remove(this.vmsObj.getLogKey());
        MDC.clear();
    }

    public boolean add(TcpServerSendData data) {
        boolean result = true;
        try {
            //offer => full -> return
            //add   => full -> wait
            //큐가 차더라도 바로 리턴함.
            if (!this.reqCommandBlockingQueue.offer(data)) {
                log.error("TcpServerReqDataProcess[{}].add: QueueFull: {}", this.vmsObj.getVmsCtlrNmbr(), this.reqCommandBlockingQueue.size());
                result = false;
            }
        } catch (Exception e) {
            log.error("TcpServerReqDataProcess[{}].add: QueueError: {}", this.vmsObj.getVmsCtlrNmbr(), e.getMessage());
            result = false;
        }
        return result;
    }

}
