package com.weather.modules.sys.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.weather.common.constant.Constant;
import com.weather.common.page.PageData;
import com.weather.common.service.impl.BaseServiceImpl;
import com.weather.common.utils.ConvertUtils;
import cn.hutool.core.util.IdUtil;
import com.weather.modules.sys.alert.AlertCreatedEvent;
import com.weather.modules.sys.alert.AlertDeletedEvent;
import com.weather.modules.sys.alert.AlertWithdrawnEvent;
import com.weather.modules.sys.dao.SysAlertDao;
import com.weather.modules.sys.dto.SysAlertDTO;
import com.weather.modules.sys.entity.SysAlertEntity;
import com.weather.modules.sys.enums.AlertLevelEnum;
import com.weather.modules.sys.service.SysAlertService;
import com.weather.modules.sys.vo.SysAlertVO;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统通知
 */
@Service
@AllArgsConstructor
public class SysAlertServiceImpl extends BaseServiceImpl<SysAlertDao, SysAlertEntity> implements SysAlertService {

    private final ApplicationEventPublisher eventPublisher;

    @Override
    public List<SysAlertVO> getActiveAlerts() {
        List<SysAlertEntity> entities = baseDao.selectActiveAlerts();
        return toVOList(entities);
    }

    @Override
    public List<SysAlertVO> getActiveAlertsSince(Long sinceId) {
        List<SysAlertEntity> entities = baseDao.selectActiveAlertsSince(sinceId);
        return toVOList(entities);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean publishIfNotExists(String level, String title, String content,
                                      String sourceType, String sourceId) {
        if (!AlertLevelEnum.isValid(level)) {
            level = AlertLevelEnum.INFO.getValue();
        }
        if (StrUtil.isNotBlank(sourceId)) {
            int count = baseDao.countBySource(sourceType, sourceId);
            if (count > 0) {
                return false;
            }
        }
        SysAlertEntity entity = new SysAlertEntity();
        entity.setId(IdUtil.getSnowflakeNextId());
        entity.setLevel(level);
        entity.setTitle(title);
        entity.setContent(content);
        entity.setSourceType(sourceType);
        entity.setSourceId(sourceId);
        entity.setIsActive(1);
        entity.setPublishTime(new Date());
        entity.setCreateDate(new Date());
        insert(entity);
        eventPublisher.publishEvent(new AlertCreatedEvent(toVO(entity)));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdraw(Long id) {
        SysAlertEntity entity = new SysAlertEntity();
        entity.setId(id);
        entity.setIsActive(0);
        entity.setUpdateDate(new Date());
        updateById(entity);
        eventPublisher.publishEvent(new AlertWithdrawnEvent(id));
    }

    @Override
    public PageData<SysAlertVO> pageAlerts(Map<String, Object> params) {
        IPage<SysAlertEntity> page = baseDao.selectPage(
                getPage(params, "publish_time", false),
                getWrapper(params)
        );
        List<SysAlertVO> voList = toVOList(page.getRecords());
        PageData<SysAlertVO> pageData = new PageData<>(voList, page.getTotal());
        return pageData;
    }

    private QueryWrapper<SysAlertEntity> getWrapper(Map<String, Object> params) {
        String level = (String) params.get("level");
        String title = (String) params.get("title");
        String sourceType = (String) params.get("sourceType");

        QueryWrapper<SysAlertEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("is_active", 1);
        wrapper.eq(StrUtil.isNotBlank(level), "level", level);
        wrapper.like(StrUtil.isNotBlank(title), "title", title);
        wrapper.eq(StrUtil.isNotBlank(sourceType), "source_type", sourceType);
        return wrapper;
    }

    @Override
    public SysAlertVO get(Long id) {
        SysAlertEntity entity = baseDao.selectById(id);
        return toVO(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysAlertDTO dto) {
        SysAlertEntity entity = ConvertUtils.sourceToTarget(dto, SysAlertEntity.class);
        entity.setId(IdUtil.getSnowflakeNextId());
        entity.setIsActive(1);
        entity.setSourceType(StrUtil.blankToDefault(dto.getSourceType(), "manual"));
        entity.setPublishTime(new Date());
        entity.setCreateDate(new Date());
        insert(entity);
        eventPublisher.publishEvent(new AlertCreatedEvent(toVO(entity)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysAlertDTO dto) {
        SysAlertEntity entity = ConvertUtils.sourceToTarget(dto, SysAlertEntity.class);
        entity.setUpdateDate(new Date());
        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long[] ids) {
        deleteBatchIds(Arrays.asList(ids));
        eventPublisher.publishEvent(new AlertDeletedEvent(ids));
    }

    // ===== 工具方法 =====

    private SysAlertVO toVO(SysAlertEntity entity) {
        if (entity == null) return null;
        SysAlertVO vo = new SysAlertVO();
        vo.setId(String.valueOf(entity.getId()));
        vo.setLevel(entity.getLevel());
        vo.setTitle(entity.getTitle());
        vo.setContent(entity.getContent());
        vo.setSourceType(entity.getSourceType());
        vo.setPublishTime(entity.getPublishTime() != null
                ? DateUtil.formatDateTime(entity.getPublishTime())
                : null);
        vo.setExpireTime(entity.getExpireTime() != null
                ? DateUtil.formatDateTime(entity.getExpireTime())
                : null);
        return vo;
    }

    private List<SysAlertVO> toVOList(List<SysAlertEntity> entities) {
        return entities.stream().map(this::toVO).collect(Collectors.toList());
    }
}
