package com.zcloud.zcGbsServicer.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo;
import com.zcloud.zcGbsServicer.api.FireBrigadeServiceI;
import com.zcloud.zcGbsServicer.command.convertor.FireBrigadeCoConvertor;
import com.zcloud.zcGbsServicer.dto.FireBrigadeAddCmd;
import com.zcloud.zcGbsServicer.dto.FireBrigadeOnlineStatusQry;
import com.zcloud.zcGbsServicer.dto.FireBrigadePageQry;
import com.zcloud.zcGbsServicer.dto.FireBrigadeUpdateCmd;
import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeCO;
import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeOnlineStatusCO;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeDO;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeUserDO;
import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeRepository;
import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeUserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class FireBrigadeServiceImpl extends FireAlarmServiceSupport implements FireBrigadeServiceI {

    private final FireBrigadeRepository fireBrigadeRepository;
    private final FireBrigadeUserRepository fireBrigadeUserRepository;
    private final FireAlarmUserResolver fireAlarmUserResolver;
    private final FireBrigadeOnlineStatusService fireBrigadeOnlineStatusService;
    private final FireBrigadeCoConvertor fireBrigadeCoConvertor;

    @Override
    public PageResponse<FireBrigadeCO> listPage(FireBrigadePageQry qry) {
        Map<String, Object> params = new HashMap<>();
        params.put("pageIndex", qry.getPageIndex());
        params.put("pageSize", qry.getPageSize());
        params.put("brigadeName", qry.getName());
        PageResponse<FireBrigadeDO> page = fireBrigadeRepository.listPage(params);
        Map<Long, ZcloudUserCo> userMap = getLeaderUserMap(page.getData());
        List<String> brigadeBizIds = page.getData().stream()
                .map(FireBrigadeDO::getFireBrigadeId)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());
        Map<String, Integer> memberCountMap = fireBrigadeUserRepository.countByFireBrigadeIds(brigadeBizIds);
        Map<String, Boolean> onlineMap = fireBrigadeOnlineStatusService.getOnlineMapForList(brigadeBizIds, currentTenantId());
        List<FireBrigadeCO> data = page.getData().stream()
                .map(item -> buildCO(item, userMap, onlineMap, memberCountMap))
                .collect(Collectors.toList());
        fireBrigadeOnlineStatusService.scheduleRefreshOnlineMap(page.getData());
        return PageResponse.of(data, page.getTotalCount(), page.getPageSize(), page.getPageIndex());
    }

    @Override
    public SingleResponse<List<FireBrigadeOnlineStatusCO>> queryOnlineStatus(FireBrigadeOnlineStatusQry qry) {
        List<String> fireBrigadeIds = qry == null || qry.getFireBrigadeIds() == null
                ? Collections.emptyList()
                : new ArrayList<>(qry.getFireBrigadeIds().stream()
                .filter(StrUtil::isNotBlank)
                .map(String::trim)
                .collect(Collectors.toCollection(LinkedHashSet::new)));
        if (fireBrigadeIds.isEmpty()) {
            return SingleResponse.of(Collections.emptyList());
        }

        List<FireBrigadeDO> brigades = fireBrigadeRepository.listByFireBrigadeIds(fireBrigadeIds);
        Map<String, Boolean> onlineMap = fireBrigadeOnlineStatusService.refreshOnlineMap(brigades);
        List<FireBrigadeOnlineStatusCO> data = fireBrigadeIds.stream()
                .map(fireBrigadeId -> {
                    FireBrigadeOnlineStatusCO co = new FireBrigadeOnlineStatusCO();
                    co.setFireBrigadeId(fireBrigadeId);
                    boolean online = Boolean.TRUE.equals(onlineMap.get(fireBrigadeId));
                    co.setOnline(online);
                    co.setOnlineText(online ? "在线" : "未在线");
                    return co;
                })
                .collect(Collectors.toList());
        return SingleResponse.of(data);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SingleResponse<FireBrigadeCO> add(FireBrigadeAddCmd cmd) {
        if (fireBrigadeRepository.existsByBrigadeName(cmd.getName(), null)) {
            throw new BizException("消防队伍名称已存在");
        }
        if (cmd.getLeaderUserId() == null) {
            throw new BizException("负责人用户ID不能为空");
        }
        FireBrigadeDO brigade = new FireBrigadeDO();
        brigade.setId(nextId());
        brigade.setFireBrigadeId(nextBizId());
        fillCreateAudit(brigade);
        fillBrigade(brigade, cmd);
        fireBrigadeRepository.save(brigade);
        // ensureLeaderRelation(brigade); // 新增队伍时不再自动创建负责人成员记录，后续单独维护
        return SingleResponse.of(buildCO(brigade,
                getLeaderUserMap(Collections.singletonList(brigade)),
                fireBrigadeOnlineStatusService.refreshOnlineMap(Collections.singletonList(brigade)),
                fireBrigadeUserRepository.countByFireBrigadeIds(Collections.singletonList(brigade.getFireBrigadeId()))));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(FireBrigadeUpdateCmd cmd) {
        FireBrigadeDO brigade = fireBrigadeRepository.getById(cmd.getId());
        if (brigade == null) {
            throw new BizException("消防队伍不存在");
        }
        if (fireBrigadeRepository.existsByBrigadeName(cmd.getName(), cmd.getId())) {
            throw new BizException("消防队伍名称已存在");
        }
        if (cmd.getLeaderUserId() == null) {
            throw new BizException("负责人用户ID不能为空");
        }
        fillUpdateAudit(brigade);
        fillBrigade(brigade, cmd);
        fireBrigadeRepository.updateById(brigade);
        // ensureLeaderRelation(brigade); // 编辑队伍时不再自动维护负责人成员记录，后续单独维护
    }

    @Override
    public FireBrigadeCO get(Long id) {
        FireBrigadeDO brigade = fireBrigadeRepository.getById(id);
        if (brigade == null) {
            throw new BizException("消防队伍不存在");
        }
        List<FireBrigadeDO> brigades = Collections.singletonList(brigade);
        List<String> brigadeBizIds = Collections.singletonList(brigade.getFireBrigadeId());
        Map<String, Boolean> onlineMap = fireBrigadeOnlineStatusService.getOnlineMapForList(brigadeBizIds, currentTenantId());
        FireBrigadeCO co = buildCO(brigade,
                getLeaderUserMap(brigades),
                onlineMap,
                fireBrigadeUserRepository.countByFireBrigadeIds(brigadeBizIds));
        fireBrigadeOnlineStatusService.scheduleRefreshOnlineMap(brigades);
        return co;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Long id) {
        FireBrigadeDO brigade = fireBrigadeRepository.getById(id);
        if (brigade == null) {
            throw new BizException("消防队伍不存在");
        }
        List<FireBrigadeUserDO> relations = fireBrigadeUserRepository.listByFireBrigadeId(brigade.getFireBrigadeId());
        if (!relations.isEmpty()) {
            fireBrigadeUserRepository.removeBatchByIds(relations.stream().map(FireBrigadeUserDO::getId).collect(Collectors.toList()));
        }
        fireBrigadeRepository.removeById(id);
    }

    private void fillBrigade(FireBrigadeDO brigade, FireBrigadeAddCmd cmd) {
        brigade.setBrigadeName(cmd.getName());
        brigade.setLeaderUserId(cmd.getLeaderUserId());
        brigade.setLeaderName(cmd.getLeader());
        brigade.setLeaderPhone(cmd.getLeaderPhone());
        brigade.setLeaderDeptName(cmd.getLeaderDept());
        brigade.setOrgName(cmd.getOrg());
        brigade.setAddress(cmd.getAddress());
        brigade.setDutyPhone(cmd.getDutyPhone());
        brigade.setEstablishDate(cmd.getFounded());
        brigade.setVehicleCount(cmd.getVehicles());
        brigade.setBrigadeInfo(cmd.getDesc());
    }

    private void ensureLeaderRelation(FireBrigadeDO brigade) {
        if (brigade.getLeaderUserId() == null) {
            return;
        }
        List<FireBrigadeUserDO> relations = fireBrigadeUserRepository.listByFireBrigadeId(brigade.getFireBrigadeId());
        FireBrigadeUserDO relation = relations.stream()
                .filter(item -> brigade.getLeaderUserId().equals(item.getUserId()))
                .findFirst()
                .orElse(null);
        if (relation == null) {
            relation = new FireBrigadeUserDO();
            relation.setId(nextId());
            relation.setFireBrigadeUserId(nextBizId());
            relation.setFireBrigadeId(brigade.getFireBrigadeId());
            relation.setUserId(brigade.getLeaderUserId());
            fillLeaderSnapshot(relation, brigade);
            fillCreateAudit(relation);
            fireBrigadeUserRepository.save(relation);
            return;
        }
        fillLeaderSnapshot(relation, brigade);
        fillUpdateAudit(relation);
        fireBrigadeUserRepository.updateById(relation);
    }

    private void fillLeaderSnapshot(FireBrigadeUserDO relation, FireBrigadeDO brigade) {
        relation.setUserName(brigade.getLeaderName());
        relation.setPhone(brigade.getLeaderPhone());
        relation.setDutyId(null);
        relation.setDutyName("负责人");
        relation.setCorpId(null);
        relation.setOrgName(brigade.getLeaderDeptName());
    }

    private FireBrigadeCO buildCO(FireBrigadeDO brigade, Map<Long, ZcloudUserCo> userMap,
                                  Map<String, Boolean> onlineMap, Map<String, Integer> memberCountMap) {
        FireBrigadeCO co = fireBrigadeCoConvertor.converDOToCO(brigade);
        ZcloudUserCo leader = brigade.getLeaderUserId() == null ? null : userMap.get(brigade.getLeaderUserId());
        co.setLeaderDeptName(selectText(leader == null ? null : leader.getDepartmentName(), co.getLeaderDeptName()));
        co.setLeaderName(selectText(leader == null ? null : leader.getName(), co.getLeaderName()));
        co.setLeaderPhone(selectText(leader == null ? null : leader.getPhone(), co.getLeaderPhone()));
        co.setOrg(brigade.getOrgName());
        co.setMemberCount(memberCountMap == null ? 0 : memberCountMap.getOrDefault(brigade.getFireBrigadeId(), 0));
        boolean online = onlineMap != null && Boolean.TRUE.equals(onlineMap.get(brigade.getFireBrigadeId()));
        co.setOnline(online);
        co.setOnlineText(online ? "在线" : "未在线");
        return co;
    }

    private String selectText(String preferred, String fallback) {
        return StrUtil.isNotBlank(preferred) ? preferred : fallback;
    }

    private Map<Long, ZcloudUserCo> getLeaderUserMap(List<FireBrigadeDO> brigades) {
        Set<Long> userIds = brigades.stream()
                .map(FireBrigadeDO::getLeaderUserId)
                .filter(java.util.Objects::nonNull)
                .collect(Collectors.toSet());
        return fireAlarmUserResolver.getUserMap(userIds);
    }

    private long nextId() {
        return IdUtil.getSnowflake(1, 1).nextId();
    }

    private String nextBizId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
