package cn.lihongjie.coal.acAppointment.listener;

import cn.lihongjie.coal.acAppointment.entity.AcAppointmentEntity;
import cn.lihongjie.coal.acAppointment.service.AcAppointmentService;
import cn.lihongjie.coal.acDevice.service.AcDeviceService;
import cn.lihongjie.coal.acDeviceData.service.AcDeviceDataService;
import cn.lihongjie.coal.dataCollector.service.DataCollectorService;
import cn.lihongjie.coal.dataCollectorLog.service.DataCollectorLogService;
import cn.lihongjie.coal.rabbitmq.RabbitMQConfiguration;
import cn.lihongjie.coal.rabbitmq.RabbitMQService;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

@Component
@Slf4j
public class AcAppointmentListener {

    @Autowired DataCollectorService dataCollectorService;

    @Autowired DataCollectorLogService dataCollectorLogService;

    @Autowired ObjectMapper objectMapper;

    @Autowired AcDeviceDataService acDeviceDataService;

    @Autowired AcDeviceService acDeviceService;
    @Autowired RabbitMQService rabbitMQService;
    @Autowired AcAppointmentService acAppointmentService;
    @Autowired AmqpAdmin amqpAdmin;

    @NotNull
    private static HashMap<Object, Object> buildMessage(
            AcAppointmentEntity appointment, String value) {
        HashMap<Object, Object> map = new HashMap<>();

        map.put("eventType", value);
        map.put("appointId", appointment.getId());
        // 客户端生成 序列 vehicleinfo_id_seq
        map.put("id", "");
        // 车牌号
        map.put("plateno", appointment.getPlateNo());
        map.put("platecolor", "1");
        map.put("platetype", "0");
        map.put("vehiclecolor", "1");
        map.put("vehicletype", "1");
        map.put("parkingtype", "0");
        map.put("cardno", "");
        map.put("brand", "");
        map.put(
                "ownername",
                StringUtils.defaultIfBlank(appointment.getDriverName(), appointment.getPlateNo()));
        map.put("owneraddress", "");
        map.put("ownerphonenumber", appointment.getDriverPhone());
        map.put("identitynumber", "");
        map.put(
                "registertime",
                LocalDateTime.now().format(RabbitMQConfiguration.DATE_TIME_FORMATTER));

        map.put(
                "begintime",
                appointment.getStartTime().format(RabbitMQConfiguration.DATE_TIME_FORMATTER));
        map.put(
                "endtime",
                appointment.getEndTime().format(RabbitMQConfiguration.DATE_TIME_FORMATTER));
        map.put("ownergender", "");
        map.put("ownerworkplace", "");
        map.put("ownerdepartment", "");
        map.put("ownerpost", "");
        // 序列 uniquenosequence
        map.put("uniquenumber", "");

        map.put("categorybelonged", "1");
        map.put("expiredhandling", "0");
        map.put("matchedhandling", "0");
        map.put("timestamp", LocalDateTime.now().format(RabbitMQConfiguration.DATE_TIME_FORMATTER));
        map.put("reserve1", "");
        map.put("reserve2", appointment.getId());
        map.put("parkpermission", "1,2,3,4,5");
        map.put("vehicleinfo_cardtype", "0");
        map.put("groupbelonged", "0");
        map.put("isalreaybag", "1");
        map.put("isfromthirdsystem", "0");
        map.put("uploadflag", "0");
        map.put("historytime", null);
        map.put(
                "extrainfo",
                """
{
"发动机号": "",
"排放量号": "",
"识别代码": "",
"车架号": "",
"车辆排量": "",
"车队名称": ""
}
""");
        return map;
    }

    @SneakyThrows
    @RabbitListener(
            bindings = {
                @QueueBinding(
                        value =
                                @org.springframework.amqp.rabbit.annotation.Queue(
                                        value = "acAppointment.data",
                                        durable = "true"),
                        exchange =
                                @Exchange(
                                        value = RabbitMQConfiguration.SYS_EXCHANGE,
                                        declare = Exchange.FALSE),
                        key = "acAppointment.*")
            })
    @Transactional
    public void handlePmsMessage(String body, @Headers Map<String, Object> headers) {

        var rk = headers.get(AmqpHeaders.RECEIVED_ROUTING_KEY).toString();

        switch (rk) {
            case "acAppointment.create":
                handleCreate(body);
                break;
            case "acAppointment.update":
                handleUpdate(body);
                break;
            case "acAppointment.delete":
                handleDelete(body);
                break;

            case "acAppointment.cancel":
                handleCancel(body);
                break;
            case "acAppointment.expire":
                handleExpire(body);
                break;

            case "acAppointment.response":
                handleResponse(body);
                break;
            default:
                log.error("unknown routing key: {}", rk);
        }
    }

    @SneakyThrows
    private void handleResponse(String body) {

        ObjectNode node = (ObjectNode) objectMapper.readTree(body);

        String appointId = node.get("appointId").asText();
        String eventType = node.get("eventType").asText();
        String status = node.get("status").asText();
        LocalDateTime time = LocalDateTime.parse(node.get("time").asText(), RabbitMQConfiguration.DATE_TIME_FORMATTER);


        AcAppointmentEntity appointment;
        try {

            appointment = acAppointmentService.get(appointId);
        } catch (Exception e) {

            log.error("appointment not exist: {}", appointId);
            return;
        }

        if (StringUtils.equals(status, "3")){
            log.info("{} fail: {}\n{}", eventType,  appointId, node.get("message").asText());
        }else {

            log.info("{}  success: {}", eventType,  appointId);
        }


        switch (eventType){


            case "acAppointment.create" ->{


                appointment.setSendFinishTime(time);
                appointment.setSendStatus(status);



            }


            case "acAppointment.update" ->{

                appointment.setSendFinishTime(time);
                appointment.setSendStatus(status);

            }

            case "acAppointment.delete" ->{


                log.info("appointment delete: {}", appointId);

            }

            case "acAppointment.cancel" ->{

                appointment.setDeleteFinishTime(time);
                appointment.setDeleteStatus(status);

            }
            case "acAppointment.expire" ->{

                appointment.setDeleteFinishTime(time);
                appointment.setDeleteStatus(status);

            }

        }


        this.acAppointmentService.save(appointment);

    }

    @SneakyThrows
    private void handleDelete(String body) {

        List<ObjectNode> values = objectMapper.readerForListOf(ObjectNode.class).readValue(body);

        for (ObjectNode value : values) {

            String id = value.get("id").asText();
            String appKey = value.get("appKey").asText();

            HashMap<Object, Object> map = new HashMap<>();
            map.put("eventType", "acAppointment.delete");
            map.put("appointId", id);

            String queueName = "pms.client." + appKey;

            rabbitMQService.send("", queueName, map, new HashMap<>());
        }
    }

    @SneakyThrows
    private void handleCancel(String body) {

        List<ObjectNode> values = objectMapper.readerForListOf(ObjectNode.class).readValue(body);

        for (ObjectNode value : values) {

            String id = value.get("id").asText();
            String appKey = value.get("appKey").asText();

            HashMap<Object, Object> map = new HashMap<>();
            map.put("eventType", "acAppointment.cancel");
            map.put("appointId", id);

            String queueName = "pms.client." + appKey;

            rabbitMQService.send("", queueName, map, new HashMap<>());
        }
    }

    @SneakyThrows
    private void handleExpire(String body) {

        List<ObjectNode> values = objectMapper.readerForListOf(ObjectNode.class).readValue(body);

        for (ObjectNode value : values) {

            String id = value.get("id").asText();
            String appKey = value.get("appKey").asText();

            HashMap<Object, Object> map = new HashMap<>();
            map.put("eventType", "acAppointment.expire");
            map.put("appointId", id);

            String queueName = "pms.client." + appKey;

            rabbitMQService.send("", queueName, map, new HashMap<>());
        }
    }

    private void handleUpdate(String body) {

        AcAppointmentEntity appointment = acAppointmentService.get(body);

        if (StringUtils.isEmpty(appointment.getSendStatus())
                || "0".equals(appointment.getSendStatus())) {
            handleCreate(body);

        } else if (StringUtils.equals("1", appointment.getSendStatus())) {

            log.info(
                    "appointment  sending: {} status {}",
                    appointment.getId(),
                    appointment.getSendStatus());

        } else if (StringUtils.equals("2", appointment.getSendStatus())) {

            doUpdate(appointment);

        } else if (StringUtils.equals("3", appointment.getSendStatus())) {

            appointment.setSendStatus("0");
            handleCreate(body);

        } else {

            log.error("unknown status: {}", appointment.getSendStatus());
        }
    }

    private void doUpdate(AcAppointmentEntity appointment) {

        HashMap<Object, Object> message = buildMessage(appointment, "acAppointment.update");

        String appKey = appointment.getDevice().getDataCollector().getAppKey();

        String queueName = "pms.client." + appKey;

        rabbitMQService.send("", queueName, message, new HashMap<>());

        appointment.setSendStatus("1");
        appointment.setSendTime(LocalDateTime.now());
        appointment.setSendFinishTime(null);
        acAppointmentService.save(appointment);
    }

    private void handleCreate(String body) {

        AcAppointmentEntity appointment = acAppointmentService.get(body);

        if (StringUtils.isEmpty(appointment.getSendStatus())
                || "0".equals(appointment.getSendStatus())) {

            String appKey = appointment.getDevice().getDataCollector().getAppKey();
            appointment.setSendStatus("1");

            HashMap<Object, Object> map = buildMessage(appointment, "acAppointment.create");

            String queueName = "pms.client." + appKey;

            rabbitMQService.send("", queueName, map, new HashMap<>());

            appointment.setSendStatus("1");
            appointment.setSendTime(LocalDateTime.now());
            appointment.setSendFinishTime(null);
            acAppointmentService.save(appointment);

        } else {

            log.info("appointment already send: {}", appointment.getId());
        }
    }
}
