package net.northking.cctp.device.api.activity;

import net.northking.cctp.device.constants.DeviceConstants;
import net.northking.cctp.device.db.entity.CdDeviceStatus;
import net.northking.cctp.device.db.entity.CdDeviceToken;
import net.northking.cctp.device.db.entity.CdDeviceUsageLog;
import net.northking.cctp.device.db.service.CdDeviceStatusService;
import net.northking.cctp.device.db.service.CdDeviceTokenService;
import net.northking.cctp.device.db.service.CdDeviceUsageLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Component
@ServerEndpoint(value = "/pub/device/achieve/WS/{uuid}")
public class DeviceActivityWS implements ApplicationContextAware {

    private Session session;

    private String deviceId;

    private static CopyOnWriteArraySet<DeviceActivityWS> socketList = new CopyOnWriteArraySet<>();

    private static CdDeviceTokenService cdDeviceTokenService;

    private static CdDeviceStatusService cdDeviceStatusService;

    private static CdDeviceUsageLogService cdDeviceUsageLogService;

    private static RedisLockRegistry redisLockRegistry;


    private final static Logger logger = LoggerFactory.getLogger(DeviceActivityWS.class);

    private static ApplicationContext context;

    @OnOpen
    public void OnOpen(Session session, @PathParam("uuid") String uuid) throws Exception {
        this.deviceId = uuid;
        this.session = session;
        socketList.add(this);
        logger.info("webSocket:设备{}------------------------------->start",uuid);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    @OnMessage
    public void OnMessage(Session session,String data) {
        try {
            logger.info("webSocket:设备{}------------------------------->接受信息:{}",this.deviceId,data);
            if (!StringUtils.isEmpty(data)){
                logger.info("webSocket:设备{}------------------------------->发送信息:{}",this.deviceId,"Pong");
                session.getBasicRemote().sendText("Pong");
            }
        } catch (Exception e) {
            logger.error("OnMessage Error:", e);
            OnClose(session);
        }
    }

    @OnClose
    public void OnClose(Session session) {
        socketList.remove(this);
        String deviceId = this.deviceId;
        CdDeviceToken deviceToken = context.getBean(CdDeviceTokenService.class).findByPrimaryKey(deviceId);
        if (!ObjectUtils.isEmpty(deviceToken)) {
            //获取redis锁
            Lock lock = null;
            if (deviceToken.getDeviceType().equals("1")) {
                lock = context.getBean(RedisLockRegistry.class).obtain(DeviceConstants.MOB_DEVICE_LOCK + deviceId);
            } else {
                lock = context.getBean(RedisLockRegistry.class).obtain(DeviceConstants.PC_DEIVCE_LOCK + deviceId);
            }
            try {
                if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) {
                    //删除token
                    int delete = context.getBean(CdDeviceTokenService.class).deleteByPrimaryKey(deviceId);
                    if (delete > 0) {
                        logger.info("释放设备:" + deviceId);
                        //更新设备使用状态
                        CdDeviceStatus status = context.getBean(CdDeviceStatusService.class).findByPrimaryKey(deviceId);
                        //使用中改成空闲
                        if (status.getUsageStatus().equals(DeviceConstants.DEVICE_STATUS_OFFLINE)) {
                            status.setUsageStatus(DeviceConstants.DEVICE_STATUS_ONLINE);
                        }else if(status.getUsageStatus().equals(DeviceConstants.DEVICE_STATUS_REMOVE)
                                && status.getDeviceStatus().equals(DeviceConstants.DEVICE_STATUS_LINK)){
                            status.setDeviceStatus(DeviceConstants.DEVICE_STATUS_LINK_ERR);
                        }
                        context.getBean(CdDeviceStatusService.class).updateByPrimaryKey(status);
                        //更新日志
                        CdDeviceUsageLog log = new CdDeviceUsageLog();
                        log.setDeviceId(deviceId);
                        log.setStartTime(deviceToken.getStartTime());
                        log.setDeviceType(deviceToken.getDeviceType());
                        List<CdDeviceUsageLog> query = context.getBean(CdDeviceUsageLogService.class).query(log);
                        if (query.size() > 0) {
                            query.get(0).setEndTime(new Date());
                            context.getBean(CdDeviceUsageLogService.class).updateByPrimaryKey(query.get(0));
                        }
                    }
                }
            } catch (InterruptedException e) {
                logger.error("释放设备异常:", e);
                Thread.currentThread().interrupt();
            } finally {
                logger.info("webSocket:设备{}------------------------------->end", deviceId);
                lock.unlock();
            }
        }
        try {
            session.close();
        } catch (IOException e) {
            logger.error("ws断开异常:", e);
        }
    }

    @OnError
    public void onError(Session session,Throwable e){
        logger.error("session:{} -------------------------->{}",session.getId(),e.getMessage());
    }
}
