package com.its.pis.entity;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.its.app.utils.SysUtils;
import com.its.pis.domain.NET;
import com.its.pis.ui.MainUI;
import com.its.pis.websocket.PisWebSocketHandlerC2C_C;
import com.its.pis.websocket.PisWebSocketSession;
import com.its.pis.websocket.message.c2f.C2FMessage;
import com.its.pis.websocket.message.c2f.C2FMessageData;
import com.its.pis.websocket.message.c2f.C2FMessageRequest;
import com.its.pis.websocket.message.c2f.PrkPlceRlTimeResponseInfo;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Getter
@Setter
@ToString
public class TbPisInfr {

	private int    index;
	private String PIS_NMBR;
	private String PIS_NM;
	private String PIS_TP;
	private String PIS_IP;
	private int PIS_PORT;
	private String PIS_END_POINT;
	private String PIS_ID;
	private String PIS_TOKEN;
	private int PIS_CYCLE;
	private String PIS_CLCT_YN;
	private String DEL_YN;
	private String connectIpAddr;
	private long lastRecvTime;

	private Map<String, TbPrkPlce>  rltnPrkPlce;
	private int 			 		netState;
	private boolean       			isDupCon;
	private boolean                 isDupLogin;

	private TbPisInfrStts 			stts;
	private PisWebSocketSession     session;
	private Channel 				dupChannel;
	private long          			syncTime;

	private C2FMessage<PrkPlceRlTimeResponseInfo> rlTimeInfo;

	private int connectCount;
	private String connectTm;
	private String disConnectTm;

	private boolean dump = false;
	private PisWebSocketHandlerC2C_C websocketClient = null;

	public Integer getId() {
		return Integer.parseInt(this.PIS_NMBR);
	}

	public TbPisInfr() {
		this.rltnPrkPlce = Collections.synchronizedMap(new HashMap<String, TbPrkPlce>());
		this.stts = new TbPisInfrStts();

		this.connectCount = 0;
		this.connectTm = "";
		this.disConnectTm = "";
		this.lastRecvTime = 0;

		initNet();
	}

	public void setLastRecvTime(long lastRecvTime) {
		this.lastRecvTime = lastRecvTime;
		MainUI mainUI = MainUI.getInstance();
		if (mainUI != null) {
			mainUI.updateCtlrStts(this);
		}
	}
	public String getLastRecvTimeFmt() {
		SimpleDateFormat sdfDate = new SimpleDateFormat("MM-dd HH:mm:ss");
		return sdfDate.format(lastRecvTime);
	}

	public PisWebSocketHandlerC2C_C createWebsocketClient() {
		if (this.websocketClient == null) {
			this.websocketClient = new PisWebSocketHandlerC2C_C(this);
			this.websocketClient.connect();
			return this.websocketClient;
		}
		return null;
	}

	public void resetConnectCount() {
		if (this.netState == NET.CLOSED)
			this.connectCount = 0;
		else
			this.connectCount = 1;
	}

	public void setConnectTm() {
		this.connectTm = SysUtils.getSysTimeStrMMDD();
		this.connectCount++;
		getStts().setCONN_DT(SysUtils.getSysTime());
	}

	public void setDisConnectTm() {
		this.disConnectTm = SysUtils.getSysTimeStrMMDD();
	}

	void initNet() {
		this.netState   = NET.CLOSED;
		this.isDupCon   = false;
		this.isDupLogin = false;
		this.session    = null;
		this.dupChannel = null;
		this.syncTime   = 0;
	}

	public synchronized void channelOpen(PisWebSocketSession session) {
		this.netState = NET.LOGIN_REQ;
		this.session = session;
		getStts().initStts(true);
		setConnectTm();
		MainUI mainUI = MainUI.getInstance();
		if (mainUI != null) {
			mainUI.updateCtlrStts(this);
		}
	}

	public synchronized void channelLogin(PisWebSocketSession session) {
		this.netState = NET.LOGINED;
		this.session = session;
		getStts().initStts(true);
		setConnectTm();
		MainUI mainUI = MainUI.getInstance();
		if (mainUI != null) {
			mainUI.updateCtlrStts(this);
		}
	}

	public synchronized void channelClosed() {
		if (this.netState != NET.CLOSED) {
			setDisConnectTm();
		}
		getStts().setDIS_CONN_DT(SysUtils.getSysTime());
		this.netState = NET.CLOSED;
		this.session = null;
		getStts().initStts(false);
		MainUI mainUI = MainUI.getInstance();
		if (mainUI != null) {
			mainUI.updateCtlrStts(this);
		}
	}

	public boolean channelClose() {
		if (getSession() == null || getNetState() == NET.CLOSED) {
			log.error("Close Request: channel not connected: [{}]", this);
			return false;
		}
		try {
			getSession().getSession().close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		MainUI mainUI = MainUI.getInstance();
		if (mainUI != null) {
			mainUI.updateCtlrStts(this);
		}
		return true;
	}

	public boolean requestRlTimeInfo() {
		if (getSession() == null || getNetState() == NET.CLOSED) {
			log.error("Reset Request: channel not connected: [{}]", this);
			return false;
		}

		C2FMessageRequest request = C2FMessageRequest.builder()
				.prk_tkn(this.PIS_TOKEN)
				.event_name("prk_plce_rl_time_request_info")
				.event_type("request")
				.build();

		C2FMessage<Object> message = C2FMessage.builder()
				.command("message")
				.data(C2FMessageData.builder()
						.payload(request)
						.build())
				.build();

		ObjectMapper mapper = new ObjectMapper();
		try {
			String strMessage = mapper.writeValueAsString(message);
			//log.info("{}", strMessage);
			TextMessage txtMessage = new TextMessage(strMessage);
			getSession().sendMessage(request.getEvent_name(), txtMessage);
		} catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}

		return true;
	}

}
