package cn.estsh.i3plus.core.apiservice.controller;

import cn.estsh.i3plus.core.api.iservice.busi.ISysRoleService;
import cn.estsh.i3plus.core.apiservice.mq.I3CoreQueueConfig;
import cn.estsh.i3plus.core.apiservice.thread.CoreDemoThread;
import cn.estsh.i3plus.platform.common.util.CommonConstWords;
import cn.estsh.i3plus.platform.common.util.PlatformConstWords;
import cn.estsh.i3plus.platform.common.util.QueueConstWords;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.platform.bean.SessionUser;
import cn.estsh.i3plus.pojo.platform.bean.SysRole;
import cn.estsh.impp.framework.base.controller.CoreBaseController;
import cn.estsh.impp.framework.boot.auth.AuthUtil;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.exception.ImppExceptionEnum;
import cn.estsh.impp.framework.boot.thread.ImppThreadPool;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import cn.estsh.impp.framework.boot.util.ResultBean;
import com.rabbitmq.client.Channel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeoutException;

/**
 * @Description :
 * @Reference :
 * @Author : alwaysfrin
 * @CreateDate : 2018-09-26 10:34
 * @Modify:
 **/
@RestController
@Api(description="复杂对象服务demo")
@RequestMapping("/demo-redis-mq")
public class DemoRedisMqController extends CoreBaseController{
    private static final Logger LOGGER = LoggerFactory.getLogger(DemoRedisMqController.class);

    /**
     * 缓存
     */
    @Resource(name="redisCore")
    private ImppRedis redisCore;

    /**
     * rabbitMQ队列
     */
    //@Autowired
    //private AmqpTemplate rabbitTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ISysRoleService sysRoleService;

    @Autowired
    private RabbitListenerEndpointRegistry rabbitRegistry;

    @Autowired
    private ConnectionFactory connectionFactory;

    /**
     * mq工厂，用于生产ack消息
     */
    @Autowired
    private CachingConnectionFactory mqFactory;

    @GetMapping(value="/get-mq-info")
    @ApiOperation(value="获取队列信息")
    public ResultBean getMqInfo(){
        System.out.println(rabbitRegistry.isAutoStartup() + "  " + rabbitRegistry.isRunning());
        System.out.println(mqFactory.isPublisherConfirms() + " " + mqFactory.isPublisherReturns());
        System.out.println(connectionFactory);

        Set<String> ids = rabbitRegistry.getListenerContainerIds();
        for(String id : ids){
            System.out.println("id = "+id);
        }

        return new ResultBean(true);
    }

    @GetMapping(value="/put-cache")
    @ApiOperation(value="缓存",notes="放入数据")
    public ResultBean putCache(){
        //放入缓存
        //redisCore.putObject("machineFactory",new MachineFactory("111","nnnn"));
        redisCore.putObject("wms","123123123");

        return new ResultBean(true,"已放入缓存");
    }

    @GetMapping(value="/get-cache")
    @ApiOperation(value="缓存",notes="获取数据")
    public ResultBean getCache(){
        System.out.println("2===== " + redisCore.getObject("wms"));

        return new ResultBean(true);
    }

    @GetMapping(value="/exception-demo")
    @ApiOperation(value="异常demo",notes="异常demo")
    public ResultBean exceptionDemp() throws IOException, TimeoutException {
        String data = "true";

        if("true".equals(data)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.WMS.getCode())
                    .setErrorCode(ImppExceptionEnum.BUSINESS_EXCEPTION_DATA_ERROR.getCode())
                    .setErrorDetail("aaa操作数据出错")
                    .setErrorSolution("检查数据完整性")
                    .build();
        }
        return new ResultBean(true,"操作成功");
    }

    @GetMapping(value="/international")
    @ApiOperation(value="国际化处理",notes="资源配置文件及国际化")
    public ResultBean international() {
        Locale locale = LocaleContextHolder.getLocale();
        System.out.println(locale.getLanguage() + "  " + locale.getCountry());

        return new ResultBean(true,"操作成功 ： " + locale.getLanguage() + "  " + locale.getCountry());
    }

    @Resource(name="redisSession")
    private ImppRedis redisSession;

    @GetMapping(value="/set-redis")
    @ApiOperation(value="setredis")
    public ResultBean setRedis(String key,String value) {
        //redisSession.putObject(key,value);
        //redisCore.putObject(key,value);


        ResultBean rs = new ResultBean(true,"yes");
        rs.setPager(new Pager(100));
        redisSession.putObject("rs",rs);
        redisCore.putObject("rs",rs);

        return new ResultBean(true,"操作成功 ： " + key + " : " + value);
    }

    @GetMapping(value="/get-redis")
    @ApiOperation(value="getredis")
    public ResultBean getRedis(String key) {
        Object  d1 = redisSession.getObject(key);
        System.out.println("redisSession-d1==" + d1);
        Object d2 = redisCore.getObject(key);

        if(d1 != null) {
            SessionUser sessionUser = AuthUtil.getSessionUser();
            System.out.println(sessionUser.toString());
        }

        System.out.println("redisCore-d2==" + d2);
        System.out.println(d1 == null?"null":d1.toString());
        System.out.println(d2 == null?"null":d2.toString());
        return new ResultBean(true,"操作成功 ： " + d1 + " : " + d2);
    }

    @GetMapping(value="/test-thread")
    @ApiOperation(value="testThread")
    public ResultBean testThread(String param) {
        ImppThreadPool.getThreadExcutorService().execute(new CoreDemoThread(param));

        return new ResultBean(true,"操作成功");
    }



    @GetMapping(value="/send-mq")
    @ApiOperation(value="队列",notes="发送")
    public ResultBean sendMQ(String data){
        String context = "hello : " + data;

        System.out.println("发送DEMO_STR_QUEUE数据 : " + context);
        this.rabbitTemplate.convertAndSend(I3CoreQueueConfig.DEMO_STR_QUEUE, context);

        System.out.println("发送DEMO_HANDLE_QUEUE数据 : " + context);
        this.rabbitTemplate.convertAndSend(I3CoreQueueConfig.DEMO_HANDLE_QUEUE, context);

        System.out.println("发送Object数据 : " + context);
        //this.rabbitTemplate.convertAndSend(I3CoreQueueConfig.DEMO_OBJ_QUEUE, new MachineFactory("111mq","rabbit"));

        return new ResultBean(true,"操作成功");
    }

    @GetMapping(value="/get-mq-handle")
    @ApiOperation(value="手动获取队列",notes="接收队列")
    public ResultBean getHandleMQ(){
        Object data = this.rabbitTemplate.receiveAndConvert(I3CoreQueueConfig.DEMO_HANDLE_QUEUE);
        if(data != null) {
            LOGGER.info("获取队列数据：" + data);
        }

        Object message = this.rabbitTemplate.receiveAndConvert(I3CoreQueueConfig.DEMO_STR_QUEUE);
        if(message != null){
            LOGGER.info("获取str数据：" + data);
        }

        message = this.rabbitTemplate.receiveAndConvert(I3CoreQueueConfig.DEMO_OBJ_QUEUE);
        if(message != null){
            LOGGER.info("获取obj数据：" + data);
        }

        return new ResultBean(true,"");
    }

    /**
     * 有确认或返回的队列
     * @param type
     * @param data
     * @return
     * @throws IOException
     * @throws TimeoutException
     */
    @GetMapping(value="/send-returnmsg")
    @ApiOperation(value="队列返回信息",notes="发送")
    public ResultBean sendReturnMQ(int type,String data) throws IOException, TimeoutException {
        if(type == 1) {
            System.out.println("===== in confirm ========");
            rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
                System.out.println("===ReturnSenderDemo ack==="+ack);
                if (ack) {
                    System.out.println("ReturnSenderDemo:消息发送成功 ");
                } else {
                    System.out.println("ReturnSenderDemo:" + cause + correlationData.toString());
                }
            });
        }else{
            System.out.println("===== in return ========");
            rabbitTemplate.setReturnCallback((Message message, int i, String s, String s1, String s2) -> {
                System.out.println("===ConfirmSenderDemo ack==="+message);
                System.out.println("i=" + i + ",s=" + s + ",s1=" + s1 + ",s2=" + s2);
            });
        }
        String returnMsg = (String) rabbitTemplate.convertSendAndReceive(I3CoreQueueConfig.DEMO_RETURN_QUEUE, data);
        System.out.println("===返回数据==="+returnMsg);
        return new ResultBean(true,"操作成功");
    }

    /**
     * 如果需要进行ack操作，需要添加RabbitListener方法
     * @return
     * @throws IOException
     * @throws TimeoutException
     */
    @GetMapping(value="/send-ackmsg")
    @ApiOperation(value="ack队列",notes="发送")
    public ResultBean sendAckMQ(String data) throws IOException, TimeoutException {
        System.out.println("发送ack数据 : " + data);
        this.rabbitTemplate.convertAndSend(I3CoreQueueConfig.DEMO_ACK_QUEUE, data);

        return new ResultBean(true,"操作成功");
    }

    @GetMapping(value="/get-ackmsg")
    @ApiOperation(value="getack队列",notes="接收")
    public ResultBean getAckMQ() throws IOException, TimeoutException {
        Channel channel = this.rabbitTemplate.getConnectionFactory().createConnection().createChannel(false);
        LOGGER.info("channel = {}",channel);
        String str = (String) rabbitTemplate.receiveAndConvert(I3CoreQueueConfig.DEMO_ACK_QUEUE);
        LOGGER.info("str = {}",str);

        Message message = rabbitTemplate.receive(I3CoreQueueConfig.DEMO_ACK_QUEUE);
        LOGGER.info("message = {}",message);
        try {
            /*String data = (String) this.rabbitTemplate.receiveAndConvert(I3CoreQueueConfig.DEMO_ACK_QUEUE);
            System.out.println("【client】数据接收成功：" + data);

            if("ack".equals(data)){
                System.out.println("【client】数据抛出异常");
                throw new RuntimeException("【队列抛出异常】" + data);
            }*/

            String data = (String) this.rabbitTemplate.receiveAndConvert(I3CoreQueueConfig.DEMO_ACK_QUEUE);
            System.out.println("【client】数据接收成功：" + data);

            if("ackack".equals(data)){
                System.out.println("【client】数据抛出异常");
                throw new RuntimeException("【队列抛出异常】" + data);
            }

            //在队列删掉 不会再发了 否则消息服务器以为这条消息没处理掉 后续还会在发
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
            //丢弃这条消息
            // channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
            // System.out.println("receiver fail");
            try {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return new ResultBean(true,"操作成功");
    }

    /**
     * 发送角色至mq交换机
     * @return
     * @throws IOException
     * @throws TimeoutException
     */
    @GetMapping(value="/send-mq-role")
    @ApiOperation(value="发送角色信息队列",notes="发送")
    public ResultBean sendRoleMQ(int sendCount) throws IOException, TimeoutException {
        List<SysRole> roleList = sysRoleService.findSysRoleAll();
        LOGGER.info("共有角色数：{}",roleList.size());

        //发送信息至通用交换机-》扇形交换
        SysRole sysRole;
        for(int i=0;i<sendCount;i++) {
            sysRole = roleList.get(i);
            LOGGER.info("{}次发送角色：{}",i,sysRole);
            this.rabbitTemplate.convertAndSend(QueueConstWords.QUEUE_EXCHANGE_COMMON,"", sysRole);
        }

        return new ResultBean(true,"操作成功");
    }


    /**
     * 发送角色至mq交换机（直达）
     * @return
     * @throws IOException
     * @throws TimeoutException
     */
    @GetMapping(value="/send-mq-role-direct")
    @ApiOperation(value="发送角色信息队列",notes="发送")
    public ResultBean sendRoleMQDirect(String routeKey) throws IOException, TimeoutException {
        //通过routekey来控制接收的队列
        this.rabbitTemplate.convertAndSend(QueueConstWords.QUEUE_EXCHANGE_DIRECT,routeKey, "发送信息=key：" + routeKey);

        return new ResultBean(true,"操作成功");
    }
}
