package cn.com.ty.lift.ud.neety.support;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.com.ty.lift.ud.chat.service.IChatSessionService;
import cn.com.ty.lift.ud.chat.service.ILiftCaseService;
import cn.com.ty.lift.ud.chat.service.impl.ChatSessionServiceImpl;
import cn.com.ty.lift.ud.chat.service.impl.LiftCaseServiceImpl;
import cn.com.ty.lift.ud.neety.protocol.ChatMsgDTO;
import cn.com.ty.lift.ud.neety.protocol.IMEncoder;
import cn.com.ty.lift.ud.neety.protocol.IMMessage;
import cn.com.ty.lift.ud.neety.protocol.IMP;
import cn.com.ty.lift.ud.neety.protocol.RoomVo;
import cn.com.ty.lift.ud.redis.ChatDo;
import cn.com.ty.lift.ud.redis.RedisUtil;
import cn.com.ty.lift.ud.utils.ApplicationContextUtil;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

/**
 * websoket 服务支持类
 * 
 * @author sKing
 * @Date 2020年6月12日
 */
@Lazy
@Slf4j
@Component
@DependsOn("redisUtil")
public class WebSoketSupport {

    /** 记录在线用户 */
    protected static ChannelGroup onlineUsers = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /** 用户名 */
    protected final AttributeKey<String> USERID = AttributeKey.valueOf("USERID");
    /** 用户名 */
    protected final AttributeKey<String> USERNAME = AttributeKey.valueOf("username");
    /** 头像 */
    protected final AttributeKey<String> HEAD_PIC = AttributeKey.valueOf("headPic");
    /** ip */
    protected final AttributeKey<String> IP_ADDR = AttributeKey.valueOf("ipAddr");

    protected final AttributeKey<JSONObject> ATTRS = AttributeKey.valueOf("attrs");
    /** 房间号 */
    protected final AttributeKey<String> ROOM = AttributeKey.valueOf("ROOM");
    /** 当前用户id */
    protected final AttributeKey<String> SENDID = AttributeKey.valueOf("SENDID");
    //用户与连接关系 key==userId
    protected static Map<String, Channel> userChannel = new ConcurrentHashMap<>();

    /** 小房间用户关系对应 */
    protected static Map<String, Set<Channel>> roomUser = new HashMap<>();
    //房间与用户之间的关系，
    protected static Map<String, Set<HashMap<String, Channel>>> roomUserChannel = new ConcurrentHashMap<>();
    /** redis缓存 */
    protected static RedisUtil redis = ApplicationContextUtil.getBean(RedisUtil.class);

    protected static IChatSessionService sessionService = ApplicationContextUtil.getBean(ChatSessionServiceImpl.class);

    protected static ILiftCaseService liftCaseService = ApplicationContextUtil.getBean(LiftCaseServiceImpl.class);
    /** 解析模式（本地测试为：false） */
    protected final static boolean testFlag = true;

    /** redis大房间key：ROOM */
    protected final String MAX_ROOM = "ROOM";

    /**
     * 获取用户昵称
     * 
     * @param client
     * @return
     */
    public String getNickName(Channel client) {
        return client.attr(USERNAME).get();
    }

    /**
     * 获取用户远程IP地址
     * 
     * @param client
     * @return
     */
    protected String getAddress(Channel client) {
        return client.remoteAddress().toString().replaceFirst("/", "");
    }

    /**
     * 获取扩展属性
     * 
     * @param client
     * @return
     */
    protected JSONObject getAttrs(Channel client) {
        try {
            return client.attr(ATTRS).get();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取扩展属性
     * 
     * @param client
     * @return
     */
    protected void setAttrs(Channel client, String key, Object value) {
        try {
            JSONObject json = client.attr(ATTRS).get();
            json.put(key, value);
            client.attr(ATTRS).set(json);
        } catch (Exception e) {
            JSONObject json = new JSONObject();
            json.put(key, value);
            client.attr(ATTRS).set(json);
        }
    }

    /**
     * 登出通知
     * 
     * @param client
     */
    public void logout(Channel client) {
        String userId = client.attr(USERID).get();
        if (userChannel.isEmpty()){
            client.pipeline().close();
        }
        if (!userChannel.isEmpty() && userChannel.containsKey(userId)){
            userChannel.remove(userId);
            client.pipeline().close();
        }

        /*String room = client.attr(ROOM).get();
        String sendId = client.attr(SENDID).get();
        Map<String, List<RoomVo>> redisRoom = redis.get(MAX_ROOM, HashMap.class);
        String txt = redis.getKey(MAX_ROOM);

        IMMessage request = new IMMessage();
        request.setName(client.attr(USERNAME).get());
        request.setCmd(IMP.SYSTEM.getName());
        request.setOnline(0);
        request.setSessionid(client.attr(ROOM).get());

        Set<Channel> minRoom = null;
        if (null != roomUser.get(request.getSessionid())) {
            minRoom = roomUser.get(request.getSessionid());
        } else {
            minRoom = new HashSet<>();
        }

        List<String> DBsessionList = sessionService.findListByUserId(sendId);
        if (null != DBsessionList) {

            // 拿到该用户的所有房间的会话列表以及未读消息列表
            Map allMsg = JSONObject.parseObject(txt, HashMap.class);
            if (null != allMsg) {

                for (String sessionKey : DBsessionList) {
                    Object keyValue = allMsg.get(sessionKey);
                    List<RoomVo> voList = new ArrayList<>();
                    if (null != keyValue) {
                        voList = JSONArray.parseArray(keyValue.toString(), RoomVo.class);
                        for (RoomVo item : voList) {
                            if (item.getUserId().equals(sendId)) {
                                item.setFlag(false);
                                redisRoom.put(sessionKey, voList);
                                log.info("房间号:{}-用户ID:{}用户下线", sessionKey, sendId);
                            }
                        }

                        String loginList = JSONObject.toJSONString(voList);
                        request.setMsg(loginList);
                        // 向小房间内的所有用户发送系统消息
                        for (Channel channel : minRoom) {
                            if (channel != client) {
                                // 发送消息
                                sendMessage(channel, request);
                            }
                        }
                    }

                }
            }
        }

        // 更新缓存数据
        redis.setValue(MAX_ROOM, redisRoom);

        // 删除用户信息
        minRoom.remove(client);
        // 当前小房间没有用户了。删除小房间
        if (minRoom.size() <= 0) {
            roomUser.remove(room);
        }

        client.close();*/
    }

    /**
     * 系统当前时间
     * 
     * @return
     */
    protected long sysTime() {
        return System.currentTimeMillis();
    }

    protected static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    /**
     * 向房间内在线用户发送其它人的在线状况支持
     * 
     * @param channel
     * @param loginList
     */
    protected void sendOnline(Channel channel, String loginList) {
        // 自定义IM协议解码
        IMMessage request = new IMMessage(IMP.SYSTEM.getName(), sysTime(), 0, loginList);
        String text = IMEncoder.toJsonString(request, testFlag);
        // 发送消息
        channel.writeAndFlush(new TextWebSocketFrame(text));
    }

    /**
     * 发送文本消息
     * 
     * @param channel
     * @param request
     */
    protected void sendMessage(Channel channel, IMMessage request) {
        // 自定义IM协议解码
        String text = IMEncoder.toJsonString(request, testFlag);
        log.info("给channel：{}发送消息",channel.id());
        // 发送消息
        channel.writeAndFlush(new TextWebSocketFrame(text));
    }

    /**
     * 提取缓存中还未同步到数据库的聊天记录，追加上新的聊天记录 如果缓存中没有历史聊天记录创建新的缓存对象
     * 
     * @param request
     *            请求对象
     * @return 消息对象
     */
    protected ChatMsgDTO saveMsg(IMMessage request) {
        if (StringUtils.isNotBlank(redis.getKey(request.getSessionid()))) {/** 提取缓存中还未同步到数据库的聊天记录，追加上新的聊天记录 */
            ChatDo chatDo = redis.get(request.getSessionid(), ChatDo.class);
            return this.saveMsg(chatDo, request.getFromUser(), request.getMsg(), 1, request.getType(),
                request.getSessionid(), request.getName(), request.getAvatarUrl());

        } else {/** 如果缓存中没有历史聊天记录创建新的缓存对象 */
            return this.saveMsg(new ChatDo(), request.getFromUser(), request.getMsg(), 1, request.getType(),
                request.getSessionid(), request.getName(), request.getAvatarUrl());
        }
    }

    /**
     * 将聊天记录存入缓存中
     * 
     * @param chatDo
     *            聊天记录
     * @param sendUserId
     *            发送人id
     * @param msg
     *            文本信息
     * @param status
     *            状态 0:正常1:屏蔽
     * @param type
     *            消息类型：1文本、2图片、3视频、4语音'
     * @param sessionid
     *            房间号号'
     */
    protected ChatMsgDTO saveMsg(ChatDo chatDo, String sendUserId, String msg, Integer status, Integer type,
        String sessionid, String name, String avatarUrl) {
        ChatMsgDTO entity = new ChatMsgDTO();
        entity.setMsg(msg);
        entity.setStatuz(status);
        entity.setName(name);
        entity.setSessionid(sessionid);
        entity.setType(type);
        entity.setFromUser(sendUserId);
        entity.setAvatarUrl(avatarUrl);
        entity.setCreateTime(LocalDateTime.now().toString());
        chatDo.getList().add(entity);

        redis.setValue(sessionid, chatDo);
        return entity;
    }

}
