package com.huimv.employment.service.notification;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huimv.employment.common.exception.BizException;
import com.huimv.employment.common.exception.ErrorCode;
import com.huimv.employment.dao.entity.FeEmploymentOrder;
import com.huimv.employment.dao.entity.FeNotification;
import com.huimv.employment.dao.entity.FeSettlementOrder;
import com.huimv.employment.dao.mapper.FeNotificationMapper;
import com.huimv.employment.service.notification.dto.NotificationItemResponse;
import com.huimv.employment.service.notification.dto.NotificationPageResponse;
import com.huimv.employment.service.notification.dto.NotificationReadResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 消息与待办中心：写入与查询 {@code fe_notification}。
 */
@Service
public class NotificationService {

    private static final Logger log = LoggerFactory.getLogger(NotificationService.class);

    private static final String TYPE_PENDING = "pending";
    private static final String CATEGORY_SETTLEMENT = "settlement";
    private static final String BIZ_SETTLEMENT = "settlement";

    private static final int MIN_PAGE = 1;
    private static final int MIN_SIZE = 1;
    private static final int MAX_SIZE = 100;
    private static final int DEFAULT_SIZE = 20;

    private final FeNotificationMapper feNotificationMapper;

    public NotificationService(FeNotificationMapper feNotificationMapper) {
        this.feNotificationMapper = feNotificationMapper;
    }

    /**
     * 分页查询当前用户消息与待办（按 create_time 倒序）。
     */
    public NotificationPageResponse listByUser(Long userId,
                                               String notifyType,
                                               String category,
                                               Boolean readFlag,
                                               Boolean handledFlag,
                                               Integer page,
                                               Integer size) {
        if (userId == null) {
            NotificationPageResponse empty = new NotificationPageResponse();
            empty.setItems(Collections.emptyList());
            empty.setTotal(0);
            empty.setPage(MIN_PAGE);
            empty.setSize(DEFAULT_SIZE);
            empty.setHasMore(false);
            empty.setUnreadCount(0);
            empty.setPendingCount(0);
            return empty;
        }

        int resolvedPage = page == null || page < MIN_PAGE ? MIN_PAGE : page;
        int resolvedSize = size == null || size < MIN_SIZE ? DEFAULT_SIZE : Math.min(size, MAX_SIZE);

        LambdaQueryWrapper<FeNotification> wrapper = new LambdaQueryWrapper<FeNotification>()
                .eq(FeNotification::getUserId, userId);
        if (StringUtils.hasText(notifyType)) {
            wrapper.eq(FeNotification::getNotifyType, notifyType.trim());
        }
        if (StringUtils.hasText(category)) {
            wrapper.eq(FeNotification::getCategory, category.trim());
        }
        if (readFlag != null) {
            wrapper.eq(FeNotification::getReadFlag, readFlag);
        }
        if (handledFlag != null) {
            wrapper.eq(FeNotification::getHandledFlag, handledFlag);
        }
        wrapper.orderByDesc(FeNotification::getCreateTime).orderByDesc(FeNotification::getId);

        Page<FeNotification> result = feNotificationMapper.selectPage(
                new Page<>(resolvedPage, resolvedSize), wrapper);

        NotificationPageResponse response = new NotificationPageResponse();
        response.setItems(result.getRecords().stream().map(this::toItem).collect(Collectors.toList()));
        response.setTotal(result.getTotal());
        response.setPage(resolvedPage);
        response.setSize(resolvedSize);
        response.setHasMore((long) resolvedPage * resolvedSize < result.getTotal());
        response.setUnreadCount(countUnread(userId));
        response.setPendingCount(countPendingUnhandled(userId));
        return response;
    }

    /**
     * 标记消息已读：更新 {@code read_flag=true}、{@code read_time}（幂等）。
     */
    @Transactional(rollbackFor = Exception.class)
    public NotificationReadResponse markRead(Long userId, Long notificationId) {
        if (userId == null) {
            throw new BizException(ErrorCode.UNAUTHORIZED, "请先登录");
        }
        if (notificationId == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "消息 ID 不能为空");
        }
        FeNotification existing = feNotificationMapper.selectById(notificationId);
        if (existing == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "消息不存在");
        }
        if (existing.getUserId() == null || !userId.equals(existing.getUserId())) {
            throw new BizException(ErrorCode.FORBIDDEN, "无权操作该消息");
        }

        if (!Boolean.TRUE.equals(existing.getReadFlag())) {
            LocalDateTime now = LocalDateTime.now();
            FeNotification update = new FeNotification();
            update.setId(existing.getId());
            update.setReadFlag(Boolean.TRUE);
            update.setReadTime(now);
            feNotificationMapper.updateById(update);
            existing.setReadFlag(Boolean.TRUE);
            existing.setReadTime(now);
        }

        NotificationReadResponse response = new NotificationReadResponse();
        response.setItem(toItem(existing));
        response.setUnreadCount(countUnread(userId));
        return response;
    }

    private long countUnread(Long userId) {
        Long count = feNotificationMapper.selectCount(new LambdaQueryWrapper<FeNotification>()
                .eq(FeNotification::getUserId, userId)
                .eq(FeNotification::getReadFlag, Boolean.FALSE));
        return count == null ? 0L : count;
    }

    private long countPendingUnhandled(Long userId) {
        Long count = feNotificationMapper.selectCount(new LambdaQueryWrapper<FeNotification>()
                .eq(FeNotification::getUserId, userId)
                .eq(FeNotification::getNotifyType, TYPE_PENDING)
                .eq(FeNotification::getHandledFlag, Boolean.FALSE));
        return count == null ? 0L : count;
    }

    private NotificationItemResponse toItem(FeNotification n) {
        NotificationItemResponse item = new NotificationItemResponse();
        item.setId(n.getId());
        item.setEnterpriseId(n.getEnterpriseId());
        item.setNotifyType(n.getNotifyType());
        item.setCategory(n.getCategory());
        item.setTitle(n.getTitle());
        item.setContent(n.getContent());
        item.setBizType(n.getBizType());
        item.setBizId(n.getBizId());
        item.setBizNo(n.getBizNo());
        item.setActionUrl(n.getActionUrl());
        item.setReadFlag(n.getReadFlag());
        item.setHandledFlag(n.getHandledFlag());
        item.setCreateTime(n.getCreateTime());
        item.setReadTime(n.getReadTime());
        item.setHandledTime(n.getHandledTime());
        return item;
    }

    /**
     * 发起结算后推送「结算待确认」待办（幂等：同一结算单未办结待办已存在则不重复写）。
     *
     * @param recipientUserId 接收人；优先订单下单人，缺省为发起结算的企业用户
     */
    @Transactional(rollbackFor = Exception.class)
    public void pushSettlementPendingConfirm(FeEmploymentOrder order,
                                             FeSettlementOrder settlement,
                                             Long recipientUserId) {
        if (order == null || settlement == null || settlement.getId() == null) {
            return;
        }
        if (findUnhandledSettlementTodo(settlement.getId()) != null) {
            log.info("结算待确认待办已存在，跳过重复推送 settlementId={}", settlement.getId());
            return;
        }

        Long userId = recipientUserId;
        if (userId == null && order.getUserId() != null) {
            userId = order.getUserId();
        }

        String orderTitle = StringUtils.hasText(order.getTitle()) ? order.getTitle().trim() : "用工订单";
        String settlementNo = settlement.getSettlementNo() != null ? settlement.getSettlementNo() : "";
        int workerCount = settlement.getWorkerCount() != null ? settlement.getWorkerCount() : 0;
        BigDecimal total = settlement.getTotalOutflow() != null ? settlement.getTotalOutflow() : BigDecimal.ZERO;

        FeNotification n = new FeNotification();
        n.setEnterpriseId(order.getEnterpriseId());
        n.setUserId(userId);
        n.setNotifyType(TYPE_PENDING);
        n.setCategory(CATEGORY_SETTLEMENT);
        n.setTitle("结算待确认");
        n.setContent(String.format("%s（%s）已生成结算单，共 %d 人，应付 ¥%s，请确认并支付。",
                orderTitle,
                StringUtils.hasText(order.getOrderNo()) ? order.getOrderNo() : ("#" + order.getId()),
                workerCount,
                total.toPlainString()));
        n.setBizType(BIZ_SETTLEMENT);
        n.setBizId(settlement.getId());
        n.setBizNo(settlementNo);
        n.setActionUrl("/packageA/chat/index?open=settlement&order_id=" + order.getId()
                + "&settlement_id=" + settlement.getId());
        n.setReadFlag(Boolean.FALSE);
        n.setHandledFlag(Boolean.FALSE);
        n.setCreateTime(LocalDateTime.now());
        feNotificationMapper.insert(n);
        log.info("已推送结算待确认待办 notificationId={} settlementId={} userId={} enterpriseId={}",
                n.getId(), settlement.getId(), userId, order.getEnterpriseId());
    }

    /**
     * 结算确认支付后，将对应「结算待确认」待办标记为已处理。
     */
    @Transactional(rollbackFor = Exception.class)
    public void markSettlementTodoHandled(Long settlementId) {
        if (settlementId == null) {
            return;
        }
        List<FeNotification> list = feNotificationMapper.selectList(
                new LambdaQueryWrapper<FeNotification>()
                        .eq(FeNotification::getBizType, BIZ_SETTLEMENT)
                        .eq(FeNotification::getBizId, settlementId)
                        .eq(FeNotification::getHandledFlag, Boolean.FALSE));
        if (list == null || list.isEmpty()) {
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        for (FeNotification n : list) {
            FeNotification update = new FeNotification();
            update.setId(n.getId());
            update.setHandledFlag(Boolean.TRUE);
            update.setHandledTime(now);
            if (!Boolean.TRUE.equals(n.getReadFlag())) {
                update.setReadFlag(Boolean.TRUE);
                update.setReadTime(now);
            }
            feNotificationMapper.updateById(update);
        }
        log.info("结算待办已标记处理 settlementId={} count={}", settlementId, list.size());
    }

    private FeNotification findUnhandledSettlementTodo(Long settlementId) {
        return feNotificationMapper.selectOne(new LambdaQueryWrapper<FeNotification>()
                .eq(FeNotification::getBizType, BIZ_SETTLEMENT)
                .eq(FeNotification::getBizId, settlementId)
                .eq(FeNotification::getHandledFlag, Boolean.FALSE)
                .orderByDesc(FeNotification::getId)
                .last("LIMIT 1"));
    }
}
