package com.cn;

import com.cn.config.PropertyDataBaseConfigBuilder;
import com.cn.job.PrintWordsJob;
import com.cn.listener.IMChatGroupListener;
import com.cn.processor.IMChatWsHandshakeProcessor;
import com.cn.service.IMChatLoginServiceProcessor;
import nl.basjes.shaded.org.springframework.util.CollectionUtils;
import org.jim.common.ImAio;
import org.jim.common.ImConfig;
import org.jim.common.ImConst;
import org.jim.common.ImPacket;
import org.jim.common.cache.redis.JedisTemplate;
import org.jim.common.config.PropertyImConfigBuilder;
import org.jim.common.packets.CloseReqBody;
import org.jim.common.packets.Command;
import org.jim.common.packets.User;
import org.jim.common.utils.JsonKit;
import org.jim.server.ImServerStarter;
import org.jim.server.command.CommandManager;
import org.jim.server.command.handler.CloseReqHandler;
import org.jim.server.command.handler.HandshakeReqHandler;
import org.jim.server.command.handler.JoinGroupReqHandler;
import org.jim.server.command.handler.LoginReqHandler;
import org.jim.server.enums.*;
import org.jim.server.model.ChatGroup;
import org.jim.server.model.Conversation;
import org.jim.server.model.GroupConversationMiddle;
import org.jim.server.model.VisitorDepartmentMiddle;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.Aio;
import org.tio.core.ChannelContext;
import org.tio.utils.lock.SetWithLock;

import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

/**
 * @author Darren
 * @date 2020/1/30 16:25
 */
public class ServerChatStart {

    private static JedisTemplate jedisTemplate = null;

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

    private static final String CURRENT_SYSTEM_ALL_USER_ID = "CURRENT_SYSTEM_ALL_USER_ID";

    private static final String GROUP_PROPERTY = " * ";

    static {
        try {
            jedisTemplate = JedisTemplate.me();
        } catch (Exception e) {
            logger.info("JedisTemplate初始化失败!");
            e.printStackTrace();
        }
    }

    /**
     * 项目入口
     * @param args
     * @return {@link }
     * @author Darren
     * @date 2020/1/30 16:28
     */
    public static void main(String[] args) throws Exception {
        //加载数据库配置
        PropertyDataBaseConfigBuilder.init("application.properties");
        //加载imcomfig
        ImConfig imConfig = new PropertyImConfigBuilder("jim.properties").build();

        //设置群组监听器，非必须，根据需要自己选择性实现;
        imConfig.setImGroupListener(new IMChatGroupListener());

        ImServerStarter imServerStarter = new ImServerStarter(imConfig);
        /*****************start 以下处理器根据业务需要自行添加与扩展，每个Command都可以添加扩展,此处为demo中处理**********************************/

        HandshakeReqHandler handshakeReqHandler = CommandManager.getCommand(Command.COMMAND_HANDSHAKE_REQ, HandshakeReqHandler.class);
        //添加自定义握手处理器;
        handshakeReqHandler.addProcessor(new IMChatWsHandshakeProcessor());
        LoginReqHandler loginReqHandler = CommandManager.getCommand(Command.COMMAND_LOGIN_REQ,LoginReqHandler.class);
        //添加登录业务处理器;
        loginReqHandler.addProcessor(new IMChatLoginServiceProcessor());

        /*****************end *******************************************************************************************/
        imServerStarter.start();
        //initQuartz();
        initData();

    }

    /**
     * 修改由于程序重启或关闭 而没有 走正常的 关闭请求处理器 的 user
     * @param
     * @return {@link }
     * @author Darren
     * @date 2020/2/14 12:02
     */
    private static void initData(){
        //修改由于程序重启或关闭 而没有 走正常的 关闭请求处理器 的 user
        Map<String,String> users = jedisTemplate.hashGetAll(CURRENT_SYSTEM_ALL_USER_ID);
        if(!CollectionUtils.isEmpty(users)){
            for(Map.Entry<String,String> entry : users.entrySet()){
                User user = JsonKit.toBean(entry.getValue(), User.class);
                //访问类型 (SERVICEACCOUNT 客服 / CUSTOMER 客户 / VISITOR 游客)
                String visitType = user.getVisitType();
                String[] userIdArray = {user.getId()};
                if( VisitTypeEnum.SERVICEACCOUNT.getKey().equals(visitType) ){
                    //移除客服容器中的 客服
                    String serviceAccountContainerKey
                            =  user.getExtras().getString("companyId") + ImConst.SEPARATOR
                            + user.getExtras().getString("departmentId") + ImConst.SEPARATOR
                            + VisitTypeEnum.SERVICEACCOUNT.getKey() ;
                    jedisTemplate.hashDel(serviceAccountContainerKey,userIdArray);
                    //判断 客服是否具有查看当前部门下 全部客服通话的权限
                    if( Boolean.valueOf(user.getExtras().getString("hasViewAllServiceAccount")) ){
                        String adminContainerKey = user.getExtras().getString("companyId")
                                + ImConst.SEPARATOR + user.getExtras().getString("departmentId")
                                + ImConst.SEPARATOR +  ImConst.ADMIN ;
                        jedisTemplate.listRemove(adminContainerKey,0,user.getId());
                    }
                    List<ChatGroup> chatGroups = ChatGroup.dao.find(createSelectGroupSqlByServiceAccountRoleDepartmentId(user));
                    if( org.apache.commons.collections4.CollectionUtils.isNotEmpty(chatGroups) ){
                        for (ChatGroup chatGroup : chatGroups) {
                            //客服是否是离线状态 1: 是 0: 否
                            chatGroup.set("service_account_type", ServiceAccountOfflineTypeEnum.OFF_LINE.getKey()).update();
                        }
                    }
                }
                if( !VisitTypeEnum.SERVICEACCOUNT.getKey().equals(visitType) ){
                    List<ChatGroup> chatGroups = ChatGroup.dao.find(createSelectGroupSqlByConsumerId(user));
                    if( !CollectionUtils.isEmpty(chatGroups) ){
                        for (ChatGroup chatGroup : chatGroups) {
                            //更改 group_state: 1 (群组离线状态 1: 离线 0: 在线)
                            //更改 consumer_type: 1 (客户/游客 离线状态 1:离线 0:在线)
                            chatGroup
                                    .set("group_state", GroupStateEnum.OFF_LINE.getKey())
                                    .set("consumer_type", ConsumerTypeEnum.OFF_LINE.getKey())
                                    .update();
                            if(MessageStateEnum.NO.getKey() == chatGroup.getInt("message_state")){
                                //群组状态 为 非留言状态
                                //修改 sw_conversation 表中的  end_time 和 conversation_lenth
                                StringBuilder sql = new StringBuilder();
                                sql.append(" select * from sw_group_conversation_middle where group_id = " + chatGroup.getStr("group_id"))
                                        .append(" order by create_time desc limit 1");
                                GroupConversationMiddle groupConversation = GroupConversationMiddle.dao.findFirst(sql.toString());
                                if( null != groupConversation ){
                                    Conversation conversation = Conversation.dao.findById(groupConversation.getLong("conversation_id"));
                                    Timestamp endTime = conversation.getTimestamp("end_time");
                                    Integer conversationLenth = conversation.getInt("conversation_lenth");
                                    if( null == endTime && null == conversationLenth ){
                                        //需要更改会话结束时间 和 对话时长
                                        long currentTimeMillis = System.currentTimeMillis();
                                        //当前时间的格林威治时间 毫秒数
                                        Timestamp currentTime = new Timestamp(currentTimeMillis);
                                        Timestamp createTime = conversation.getTimestamp("create_time");
                                        //会话创建时间的格林威治时间 毫秒数
                                        long createTimeMillis = createTime.getTime();
                                        if(currentTimeMillis > createTimeMillis){
                                            conversation.set("end_time",currentTime);
                                            conversation.set("conversation_lenth",Integer.valueOf( String.valueOf( (currentTimeMillis - createTimeMillis)/1000 )));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if( VisitTypeEnum.VISITOR.getKey().equals(visitType) ){
                    //修改 sw_visitor_department_middle 表中的 online状态; '用户状态 1:已下线 0:在线'
                    VisitorDepartmentMiddle.dao.findById(user.getId()).set("online",1).update();
                }
                jedisTemplate.hashDel(CURRENT_SYSTEM_ALL_USER_ID,userIdArray);
            }
        }
    }

    private static String createSelectGroupSqlByConsumerId(User user){
        StringBuilder sql = new StringBuilder();
        sql
                .append(" select ")
                .append(GROUP_PROPERTY)
                .append(" from sw_group where 1 = 1 ")
                .append(" and company_id = " + user.getExtras().getString("companyId"))
                .append(" and department_id = " + user.getExtras().getString("departmentId"))
                .append(
                        " and consumer_id = "
                                + user.getId()
                );
        return sql.toString();
    }

    private static String createSelectGroupSqlByServiceAccountRoleDepartmentId(User user){
        StringBuilder sql = new StringBuilder();
        sql
                .append(" select ")
                .append(GROUP_PROPERTY)
                .append(" from sw_group where 1 = 1 ")
                .append(" and company_id = " + user.getExtras().getString("companyId"))
                .append(" and department_id = " + user.getExtras().getString("departmentId"))
                .append(
                        " and service_account_role_department_middle_id = "
                                + user.getId()
                );
        return sql.toString();
    }

    /**
     * 集成 quartz 定时任务启动
     * @param
     * @return {@link }
     * @author Darren
     * @date 2020/2/13 17:05
     */
    private static void initQuartz() throws SchedulerException, InterruptedException {
        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = stdSchedulerFactory.getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
                .withIdentity("job1", "group1").build();
        // 3、构建Trigger实例,每隔1s执行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .startNow()//立即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        //每隔1s执行一次
                        .withIntervalInSeconds(2)
                        //一直执行
                        .repeatForever()).build();
        //4、执行
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();
        //睡眠
        TimeUnit.MINUTES.sleep(1);
        scheduler.shutdown();
        System.out.println("--------scheduler shutdown ! ------------");
    }


}
