package cn.iocoder.yudao.module.reminder.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.common.service.InspectionNoticeService;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.constant.InspectionConstants;
import cn.iocoder.yudao.module.inspection.entity.InspectionInfo;
import cn.iocoder.yudao.module.inspection.service.IInspectionInfoService;
import cn.iocoder.yudao.module.reminder.entity.InspectionReminderConfig;
import cn.iocoder.yudao.module.reminder.entity.InspectionReminderRecord;
import cn.iocoder.yudao.module.reminder.mapper.InspectionReminderConfigMapper;
import cn.iocoder.yudao.module.reminder.service.IInspectionReminderConfigService;
import cn.iocoder.yudao.module.reminder.service.IInspectionReminderRecordService;
import cn.iocoder.yudao.module.shop.entity.ShopUserCar;
import cn.iocoder.yudao.module.shop.service.IShopUserCarService;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.util.SendSmsUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.omg.PortableInterceptor.USER_EXCEPTION;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 年审和年检提醒配置表 服务实现类
 * </p>
 *
 * @author lighting
 * @since 2025-07-21
 */
@Service
@RequiredArgsConstructor
public class InspectionReminderConfigServiceImpl extends ServiceImpl<InspectionReminderConfigMapper, InspectionReminderConfig> implements IInspectionReminderConfigService {

    private final IShopUserCarService shopUserCarService;
    private final IInspectionInfoService inspectionInfoService;
    private final InspectionNoticeService inspectionNoticeService;
    private final AdminUserService adminUserService;
    private final IInspectionReminderRecordService reminderRecordService;
    private final RoleService roleService;


    @Override
    public void expireInspectionReminder() {
        // TODO 有可能每天都会给同一辆车发送信息 只需要发送一次
        InspectionReminderConfig config = this.getOne(Wrappers.<InspectionReminderConfig>lambdaQuery());
        if (ObjectUtil.isNotEmpty(config) && config.getStatus() == 0) {
            DateTime now = DateUtil.date();
            reminderNextInspection(config.getAnnualEviewDay(), now, config);
            reminderInsurance(config.getInsuranceDay(), now, config);
        }
    }

    private void reminderInsurance(Integer insuranceDay, DateTime now, InspectionReminderConfig config) {
        DateTime insuranceTime = DateUtil.offsetDay(now, insuranceDay);
        List<ShopUserCar> insuranceReminders = shopUserCarService.list(Wrappers.<ShopUserCar>lambdaQuery()
                .between(ShopUserCar::getInsuranceDate, DateUtil.beginOfDay(now), DateUtil.endOfDay(insuranceTime))
                .or()
                .between(ShopUserCar::getVehicleInsuranceExpiryDate, DateUtil.beginOfDay(now), DateUtil.endOfDay(insuranceTime)));

        Set<String> carNos = insuranceReminders.stream().map(ShopUserCar::getCarNo).collect(Collectors.toSet());
        if (carNos.isEmpty()) return;

        List<InspectionInfo> inspectionInfos = inspectionInfoService.selectLatestByCarNums(carNos);
        Map<String, Long> othersInfo = getOthersInfo(config, inspectionInfos);

        List<String> ownerPhones = inspectionInfos.stream()
                .map(InspectionInfo::getBuyPhone)
                .filter(ObjectUtil::isNotEmpty)
                .collect(Collectors.toList());

        List<UserDTO> users = roleService.getUserListByCodes(Collections.singletonList("jcxxgly"));

        // 发送站内信
        for (InspectionInfo inspectionInfo : inspectionInfos) {
            Date minDate = Stream.of(inspectionInfo.getInsuranceExpiryDate(), inspectionInfo.getVehicleInsuranceExpiryDate())
                    .filter(Objects::nonNull)
                    .min(Date::compareTo)
                    .orElse(null);
            String formattedDate = DateUtil.format(minDate, "yyyy年MM月dd日");

            // 查询是否已有提醒记录
            Long count = reminderRecordService.count(Wrappers.<InspectionReminderRecord>lambdaQuery()
                    .eq(InspectionReminderRecord::getCarNum, inspectionInfo.getCarNum())
                    .eq(InspectionReminderRecord::getReminderType, 1) // 1表示保险
                    .eq(InspectionReminderRecord::getActualDueDate, DateUtil.beginOfDay(minDate)));

            if (count != null && count > 0) {
                ownerPhones.remove(inspectionInfo.getBuyPhone());
                continue; // 已提醒过，跳过
            }

            // 添加提醒记录
            InspectionReminderRecord record = new InspectionReminderRecord();
            record.setCarNum(inspectionInfo.getCarNum());
            record.setReminderType(1); // 保险
            record.setActualDueDate(minDate);
            record.setRemindDate(now);
            reminderRecordService.save(record);

            switch (config.getReminderPeople()) {
                case 0:
                    String msgOwner = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_INSURANCE_EXPIRE_USER, inspectionInfo.getCarNum(), formattedDate);
                    inspectionNoticeService.sentMessageToMember(inspectionInfo.getUserId(), msgOwner, null);
                    break;
                case 1:
                    Long otherUserId = othersInfo.get(inspectionInfo.getOtherPhone());
                    if (otherUserId != null) {
                        String msgAgent = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_INSURANCE_EXPIRE, inspectionInfo.getCarNum(), formattedDate, inspectionInfo.getBuyPhone());
                        sentMessage(otherUserId, msgAgent);
                    }
                    break;
                case 2:
                    inspectionNoticeService.sentMessageToMember(inspectionInfo.getUserId(),
                            String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_INSURANCE_EXPIRE_USER, inspectionInfo.getCarNum(), formattedDate), null);
                    Long otherId = othersInfo.get(inspectionInfo.getOtherPhone());
                    if (otherId != null) {
                        String msgBoth = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_INSURANCE_EXPIRE, inspectionInfo.getCarNum(), formattedDate, inspectionInfo.getBuyPhone());
                        sentMessage(otherId, msgBoth);
                    }
                    break;
            }

            // 提醒信息管理员
            if (CollUtil.isNotEmpty(users)) {
                for (UserDTO user : users) {
                    String msgBoth = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_INSURANCE_EXPIRE, inspectionInfo.getCarNum(), formattedDate, inspectionInfo.getBuyPhone());
                    inspectionNoticeService.sentMessageToMember(user.getId(), msgBoth, null);
                }
            }

        }
        // 发送短信
        sendSmsByConfig(config, ownerPhones);
    }

    private void reminderNextInspection(Integer annualEviewDay, DateTime now, InspectionReminderConfig config) {
        DateTime annualEviewTime = DateUtil.offsetDay(now, annualEviewDay);
        List<ShopUserCar> nextInspections = shopUserCarService.list(Wrappers.<ShopUserCar>lambdaQuery()
                .between(ShopUserCar::getNextInspectionDate, DateUtil.beginOfDay(now), DateUtil.endOfDay(annualEviewTime)));

        Set<String> carNos = nextInspections.stream().map(ShopUserCar::getCarNo).collect(Collectors.toSet());
        if (carNos.isEmpty()) return;

        List<InspectionInfo> inspectionInfos = inspectionInfoService.selectLatestByCarNums(carNos);
        Map<String, Long> othersInfo = getOthersInfo(config, inspectionInfos);

        List<String> ownerPhones = inspectionInfos.stream()
                .map(InspectionInfo::getBuyPhone)
                .filter(ObjectUtil::isNotEmpty)
                .collect(Collectors.toList());

        List<UserDTO> users = roleService.getUserListByCodes(Collections.singletonList("jcxxgly"));



        for (InspectionInfo inspectionInfo : inspectionInfos) {
            String formattedDate = DateUtil.format(inspectionInfo.getNextInspectionDate(), "yyyy年MM月dd日");

            // 查询是否已有提醒记录
            Long count = reminderRecordService.count(Wrappers.<InspectionReminderRecord>lambdaQuery()
                    .eq(InspectionReminderRecord::getCarNum, inspectionInfo.getCarNum())
                    .eq(InspectionReminderRecord::getReminderType, 1) // 1表示保险
                    .eq(InspectionReminderRecord::getActualDueDate, inspectionInfo.getNextInspectionDate()));

            if (count != null && count > 0) {
                ownerPhones.remove(inspectionInfo.getBuyPhone());
                continue; // 已提醒过，跳过
            }

            // 添加提醒记录
            InspectionReminderRecord record = new InspectionReminderRecord();
            record.setCarNum(inspectionInfo.getCarNum());
            record.setReminderType(1); // 保险
            record.setActualDueDate(inspectionInfo.getNextInspectionDate());
            record.setRemindDate(now);
            reminderRecordService.save(record);
            switch (config.getReminderPeople()) {
                case 0:
                    String msgOwner = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_YEAR_EXPIRE_USER, inspectionInfo.getCarNum(), formattedDate);
                    inspectionNoticeService.sentMessageToMember(inspectionInfo.getUserId(), msgOwner, null);
                    break;
                case 1:
                    Long otherUserId = othersInfo.get(inspectionInfo.getOtherPhone());
                    if (otherUserId != null) {
                        String msgAgent = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_YEAR_EXPIRE, inspectionInfo.getCarNum(), formattedDate, inspectionInfo.getBuyPhone());
                        sentMessage(otherUserId, msgAgent);
                    }
                    break;
                case 2:
                    inspectionNoticeService.sentMessageToMember(inspectionInfo.getUserId(),
                            String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_YEAR_EXPIRE_USER, inspectionInfo.getCarNum(), formattedDate), null);
                    Long otherId = othersInfo.get(inspectionInfo.getOtherPhone());
                    if (otherId != null) {
                        String msgBoth = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_YEAR_EXPIRE, inspectionInfo.getCarNum(), formattedDate, inspectionInfo.getBuyPhone());
                        sentMessage(otherId, msgBoth);
                    }
                    break;
            }

            // 提醒信息管理员
            if (CollUtil.isNotEmpty(users)) {
                for (UserDTO user : users) {
                    String msgBoth = String.format(InspectionConstants.INSPECTION_NOTICE_TEMPLATE_USER_CAR_INSURANCE_EXPIRE, inspectionInfo.getCarNum(), formattedDate, inspectionInfo.getBuyPhone());
                    inspectionNoticeService.sentMessageToMember(user.getId(), msgBoth, null);
                }
            }
        }
        sendSmsByConfig(config, ownerPhones);
    }

    /**
     * 根据配置和inspectionInfos获取经办人ID映射（手机号 -> userId）
     */
    private Map<String, Long> getOthersInfo(InspectionReminderConfig config, List<InspectionInfo> inspectionInfos) {
        if (config.getReminderPeople() != 1 && config.getReminderPeople() != 2) {
            return Collections.emptyMap();
        }

        Set<String> phones = inspectionInfos.stream()
                .map(InspectionInfo::getOtherPhone)
                .filter(ObjectUtil::isNotEmpty)
                .collect(Collectors.toSet());

        if (phones.isEmpty()) {
            return Collections.emptyMap();
        }

        List<AdminUserDO> others = adminUserService.list(Wrappers.<AdminUserDO>lambdaQuery()
                .in(AdminUserDO::getUsername, phones)
                .ne(AdminUserDO::getUserType, "02"));

        return others.stream().collect(Collectors.toMap(AdminUserDO::getUsername, AdminUserDO::getId));
    }

    /**
     * 发送短信，根据 config.reminderPeople 判断发送给谁
     */
    private void sendSmsByConfig(InspectionReminderConfig config, List<String> phoneNums) {
        if (CollUtil.isEmpty(phoneNums)) return;
        String[] phoneArray = phoneNums.toArray(new String[0]);
//        String[] phoneArray = {"19392873837"};

        switch (config.getReminderPeople()) {
            case 0: // 车主
                SendSmsUtil.sendMsgCommonByPhoneNums(null, phoneArray, config.getSdkAppId(), config.getSignName(), config.getTemplateId());
                break;
            case 1: // 经办人
                // TODO: 这里如果需要给经办人发送短信，需要传入经办人手机号
                break;
            case 2: // 车主和经办人
                SendSmsUtil.sendMsgCommonByPhoneNums(null, phoneArray, config.getSdkAppId(), config.getSignName(), config.getTemplateId());
                // TODO: 经办人手机号发送逻辑
                break;
        }
    }

    private void sentMessage(Long userId, String content) {
        inspectionNoticeService.sentMessage(userId, content);
    }
}

