package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.vpp.domain.VppCustomer;
import com.usky.vpp.domain.VppSite;
import com.usky.vpp.domain.VppSiteConfig;
import com.usky.vpp.mapper.VppCustomerMapper;
import com.usky.vpp.mapper.VppSiteConfigMapper;
import com.usky.vpp.mapper.VppSiteMapper;
import com.usky.vpp.service.VppSiteService;
import com.usky.vpp.domain.VppResourcePoint;
import com.usky.vpp.mapper.VppResourcePointMapper;
import com.usky.vpp.service.vo.SiteConfigDetailVO;
import com.usky.vpp.service.vo.SiteListVO;
import com.usky.vpp.service.vo.SiteConfigRequest;
import com.usky.vpp.service.vo.SiteRequest;
import com.usky.vpp.util.VppAuditHelper;
import com.usky.vpp.util.VppPageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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

@Service
public class VppSiteServiceImpl implements VppSiteService {

    @Autowired
    private VppSiteMapper siteMapper;
    @Autowired
    private VppSiteConfigMapper siteConfigMapper;
    @Autowired
    private VppCustomerMapper customerMapper;
    @Autowired
    private VppResourcePointMapper resourcePointMapper;

    @Override
    public CommonPage<VppSite> pageSite(Map<String, Object> params) {
        Page<VppSite> page = VppPageHelper.of(params);
        return toCommonPage(siteMapper.selectPage(page, buildSiteWrapper(params)));
    }

    @Override
    public CommonPage<SiteListVO> pageSiteList(Map<String, Object> params) {
        Page<VppSite> page = VppPageHelper.of(params);
        LambdaQueryWrapper<VppSite> wrapper = buildSiteWrapper(params);
        applyResourceTypeFilter(wrapper, params);
        Page<VppSite> result = siteMapper.selectPage(page, wrapper);
        return toSiteListPage(result);
    }

    @Override
    public VppSite getSite(Long id) {
        VppSite site = siteMapper.selectById(id);
        if (site == null || VppAuditHelper.isDeleted(site.getDeleteFlag())) {
            throw new BusinessException("站点不存在");
        }
        return site;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VppSite createSite(SiteRequest request) {
        validateSiteRequest(request, null);
        ensureCustomerExists(request.getCustomerId());
        VppSite site = new VppSite();
        applySiteRequest(site, request);
        VppAuditHelper.fillCreate(site);
        siteMapper.insert(site);
        return site;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSite(Long id, SiteRequest request) {
        VppSite existing = getSite(id);
        validateSiteRequest(request, id);
        ensureCustomerExists(request.getCustomerId());
        applySiteRequest(existing, request);
        VppAuditHelper.fillUpdate(existing);
        siteMapper.updateById(existing);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSite(Long id) {
        VppSite site = getSite(id);
        VppAuditHelper.fillSoftDelete(site);
        siteMapper.updateById(site);
    }

    @Override
    public VppSiteConfig getSiteConfig(Long siteId) {
        getSite(siteId);
        VppSiteConfig config = siteConfigMapper.selectOne(new LambdaQueryWrapper<VppSiteConfig>()
                .eq(VppSiteConfig::getSiteId, siteId)
                .eq(VppSiteConfig::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        if (config == null) {
            throw new BusinessException("站点运行参数不存在");
        }
        return config;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VppSiteConfig saveSiteConfig(Long siteId, SiteConfigRequest request) {
        getSite(siteId);
        if (request == null || request.getCollectIntervalSec() == null) {
            throw new BusinessException("采集频率不能为空");
        }
        VppSiteConfig config = siteConfigMapper.selectOne(new LambdaQueryWrapper<VppSiteConfig>()
                .eq(VppSiteConfig::getSiteId, siteId)
                .eq(VppSiteConfig::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        if (config == null) {
            config = new VppSiteConfig();
            config.setSiteId(siteId);
            applySiteConfig(config, request);
            VppAuditHelper.fillCreate(config);
            siteConfigMapper.insert(config);
        } else {
            applySiteConfig(config, request);
            VppAuditHelper.fillUpdate(config);
            siteConfigMapper.updateById(config);
        }
        return config;
    }

    @Override
    public SiteConfigDetailVO getSiteConfigDetail(Long siteId) {
        VppSite site = getSite(siteId);
        VppSiteConfig config = siteConfigMapper.selectOne(new LambdaQueryWrapper<VppSiteConfig>()
                .eq(VppSiteConfig::getSiteId, siteId)
                .eq(VppSiteConfig::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        return toConfigDetail(site, config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SiteConfigDetailVO saveSiteConfigDetail(Long siteId, SiteConfigRequest request) {
        saveSiteConfig(siteId, request);
        if (request != null && request.getResponsePriority() != null) {
            VppSite site = getSite(siteId);
            site.setResponsePriority(request.getResponsePriority());
            VppAuditHelper.fillUpdate(site);
            siteMapper.updateById(site);
        }
        return getSiteConfigDetail(siteId);
    }

    private LambdaQueryWrapper<VppSite> buildSiteWrapper(Map<String, Object> params) {
        LambdaQueryWrapper<VppSite> wrapper = new LambdaQueryWrapper<VppSite>()
                .eq(VppSite::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .eq(VppSite::getTenantId, SecurityUtils.getTenantId())
                .orderByDesc(VppSite::getCreateTime);
        if (params != null) {
            if (params.get("customerId") != null) {
                wrapper.eq(VppSite::getCustomerId, Long.parseLong(params.get("customerId").toString()));
            }
            if (params.get("siteName") != null) {
                wrapper.like(VppSite::getSiteName, params.get("siteName").toString());
            }
            if (params.get("siteCode") != null) {
                wrapper.eq(VppSite::getSiteCode, params.get("siteCode").toString());
            }
            if (params.get("province") != null && StringUtils.hasText(params.get("province").toString())) {
                wrapper.like(VppSite::getProvince, params.get("province").toString());
            }
            if (params.get("city") != null) {
                wrapper.eq(VppSite::getCity, params.get("city").toString());
            }
            if (params.get("district") != null) {
                wrapper.eq(VppSite::getDistrict, params.get("district").toString());
            }
            if (params.get("streetTown") != null) {
                wrapper.eq(VppSite::getStreetTown, params.get("streetTown").toString());
            }
        }
        return wrapper;
    }

    private void applyResourceTypeFilter(LambdaQueryWrapper<VppSite> wrapper, Map<String, Object> params) {
        if (params == null || params.get("resourceType") == null) {
            return;
        }
        List<VppResourcePoint> resources = resourcePointMapper.selectList(
                new LambdaQueryWrapper<VppResourcePoint>()
                        .eq(VppResourcePoint::getResourceType, params.get("resourceType").toString())
                        .eq(VppResourcePoint::getDeleteFlag, VppAuditHelper.NOT_DELETED));
        if (resources.isEmpty()) {
            wrapper.eq(VppSite::getId, -1L);
            return;
        }
        Set<Long> siteIds = resources.stream().map(VppResourcePoint::getSiteId).filter(Objects::nonNull).collect(Collectors.toSet());
        wrapper.in(VppSite::getId, siteIds);
    }

    private CommonPage<SiteListVO> toSiteListPage(Page<VppSite> page) {
        List<VppSite> sites = page.getRecords();
        if (sites.isEmpty()) {
            return new CommonPage<>(Collections.emptyList(), page.getTotal(), page.getCurrent(), page.getSize());
        }
        Set<Long> siteIds = sites.stream().map(VppSite::getId).collect(Collectors.toSet());
        List<VppResourcePoint> allResources = resourcePointMapper.selectList(
                new LambdaQueryWrapper<VppResourcePoint>()
                        .in(VppResourcePoint::getSiteId, siteIds)
                        .eq(VppResourcePoint::getDeleteFlag, VppAuditHelper.NOT_DELETED));
        Map<Long, List<VppResourcePoint>> resourceBySite = allResources.stream()
                .collect(Collectors.groupingBy(VppResourcePoint::getSiteId));

        List<SiteListVO> voList = new ArrayList<>();
        for (VppSite site : sites) {
            SiteListVO vo = new SiteListVO();
            vo.setId(site.getId());
            vo.setSiteCode(site.getSiteCode());
            vo.setSiteName(site.getSiteName());
            vo.setCustomerId(site.getCustomerId());
            vo.setProvince(site.getProvince());
            vo.setCity(site.getCity());
            vo.setDistrict(site.getDistrict());
            vo.setAddress(site.getAddress());
            vo.setLongitude(site.getLongitude());
            vo.setLatitude(site.getLatitude());
            vo.setOwnerName(site.getOwnerName());
            vo.setContactName(site.getContactName());
            vo.setContactPhone(site.getContactPhone());
            vo.setUnResourceId(site.getUnResourceId());
            vo.setResponsePriority(site.getResponsePriority());
            vo.setCreateTime(site.getCreateTime());
            List<VppResourcePoint> siteResources = resourceBySite.getOrDefault(site.getId(), Collections.emptyList());
            vo.setResourceCount((long) siteResources.size());
            vo.setResourceTypes(siteResources.stream()
                    .map(VppResourcePoint::getResourceType)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList()));
            vo.setAccountNo(site.getAccountNo());
            vo.setStreetTown(site.getStreetTown());
            vo.setAvgCompletionRate(site.getAvgCompletionRate());
            vo.setRunStatus(site.getRunStatus());
            voList.add(vo);
        }
        return new CommonPage<>(voList, page.getTotal(), page.getCurrent(), page.getSize());
    }

    private SiteConfigDetailVO toConfigDetail(VppSite site, VppSiteConfig config) {
        SiteConfigDetailVO detail = new SiteConfigDetailVO();
        detail.setSiteId(site.getId());
        detail.setSiteName(site.getSiteName());
        detail.setResponsePriority(site.getResponsePriority());
        if (config != null) {
            detail.setCollectIntervalSec(config.getCollectIntervalSec());
            detail.setPowerUpperLimit(config.getPowerUpperLimit());
            detail.setPowerLowerLimit(config.getPowerLowerLimit());
            detail.setSocUpperLimit(config.getSocUpperLimit());
            detail.setSocLowerLimit(config.getSocLowerLimit());
            detail.setOfflineTimeoutSec(config.getOfflineTimeoutSec());
            detail.setAlarmRuleJson(config.getAlarmRuleJson());
        }
        return detail;
    }

    private void ensureCustomerExists(Long customerId) {
        VppCustomer customer = customerMapper.selectById(customerId);
        if (customer == null || VppAuditHelper.isDeleted(customer.getDeleteFlag())) {
            throw new BusinessException("客户不存在");
        }
    }

    private void validateSiteRequest(SiteRequest request, Long excludeId) {
        if (request == null || !StringUtils.hasText(request.getSiteCode())) {
            throw new BusinessException("站点编号不能为空");
        }
        if (!StringUtils.hasText(request.getSiteName())) {
            throw new BusinessException("站点名称不能为空");
        }
        if (request.getCustomerId() == null) {
            throw new BusinessException("所属客户不能为空");
        }
        LambdaQueryWrapper<VppSite> wrapper = new LambdaQueryWrapper<VppSite>()
                .eq(VppSite::getSiteCode, request.getSiteCode())
                .eq(VppSite::getDeleteFlag, VppAuditHelper.NOT_DELETED);
        if (excludeId != null) {
            wrapper.ne(VppSite::getId, excludeId);
        }
        if (siteMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("站点编号已存在");
        }
    }

    private void applySiteRequest(VppSite site, SiteRequest request) {
        site.setSiteCode(request.getSiteCode());
        site.setSiteName(request.getSiteName());
        site.setCustomerId(request.getCustomerId());
        site.setProvince(request.getProvince());
        site.setCity(request.getCity());
        site.setDistrict(request.getDistrict());
        site.setAddress(request.getAddress());
        site.setLongitude(request.getLongitude());
        site.setLatitude(request.getLatitude());
        site.setOwnerName(request.getOwnerName());
        site.setContactName(request.getContactName());
        site.setContactPhone(request.getContactPhone());
        site.setResponsePriority(request.getResponsePriority());
        site.setUnResourceId(request.getUnResourceId());
        site.setRemark(request.getRemark());
        site.setAccountNo(request.getAccountNo());
        if(request.getStreetTown() != null) {
            site.setStreetTown(request.getStreetTown());
        }
    }

    private void applySiteConfig(VppSiteConfig config, SiteConfigRequest request) {
        config.setCollectIntervalSec(request.getCollectIntervalSec());
        config.setPowerUpperLimit(request.getPowerUpperLimit());
        config.setPowerLowerLimit(request.getPowerLowerLimit());
        config.setSocUpperLimit(request.getSocUpperLimit());
        config.setSocLowerLimit(request.getSocLowerLimit());
        config.setOfflineTimeoutSec(request.getOfflineTimeoutSec());
        config.setAlarmRuleJson(request.getAlarmRuleJson());
    }

    private CommonPage<VppSite> toCommonPage(Page<VppSite> page) {
        return new CommonPage<>(page.getRecords(), page.getTotal(), page.getCurrent(), page.getSize());
    }
}
