package org.dromara.inspection.service.impl;

import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.inspection.domain.bo.OpsInspectionReportBo;
import org.dromara.inspection.domain.vo.OpsInspectionReportRecordVo;
import org.dromara.inspection.domain.vo.OpsInspectionReportVo;
import org.dromara.inspection.service.IOpsInspectionRepairService;
import org.dromara.personnel.domain.vo.OpsUserVo;
import org.dromara.personnel.service.impl.OpsUserServiceImpl;
import org.dromara.resource.api.RemoteFileService;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.vo.RemoteUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dromara.inspection.domain.bo.OpsInspectionRepairBo;
import org.dromara.inspection.domain.vo.OpsInspectionRepairVo;
import org.dromara.inspection.domain.OpsInspectionRepair;
import org.dromara.inspection.mapper.OpsInspectionRepairMapper;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 运维-巡检-抢修Service业务层处理
 *
 * @author LionLi
 * @date 2025-09-22
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class OpsInspectionRepairServiceImpl implements IOpsInspectionRepairService {

    private final OpsInspectionRepairMapper baseMapper;

    @DubboReference
    private RemoteFileService remoteFileService;
    @DubboReference
    private RemoteUserService userService;

    /**
     * 查询运维-巡检-抢修
     *
     * @param id 主键
     * @return 运维-巡检-抢修
     */
    @Override
    public OpsInspectionRepairVo queryById(Long id){
        OpsInspectionRepairVo vo = baseMapper.selectVoById(id);
        List<OpsInspectionRepairVo> vo1 = List.of(vo);
        setValue(vo1);
        return vo1.getFirst();
    }

    /**
     * 分页查询运维-巡检-抢修列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 运维-巡检-抢修分页列表
     */
    @Override
    public TableDataInfo<OpsInspectionRepairVo> queryPageList(OpsInspectionRepairBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<OpsInspectionRepair> lqw = buildQueryWrapper(bo);
        Page<OpsInspectionRepairVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        setValue(result.getRecords());
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的运维-巡检-抢修列表
     *
     * @param bo 查询条件
     * @return 运维-巡检-抢修列表
     */
    @Override
    public List<OpsInspectionRepairVo> queryList(OpsInspectionRepairBo bo) {
        LambdaQueryWrapper<OpsInspectionRepair> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<OpsInspectionRepair> buildQueryWrapper(OpsInspectionRepairBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<OpsInspectionRepair> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(OpsInspectionRepair::getId);
        lqw.eq(bo.getProjectId() != null, OpsInspectionRepair::getProjectId, bo.getProjectId());
        lqw.eq(StringUtils.isNotBlank(bo.getLevel()), OpsInspectionRepair::getLevel, bo.getLevel());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), OpsInspectionRepair::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), OpsInspectionRepair::getType, bo.getType());
        return lqw;
    }

    /**
     * 新增运维-巡检-抢修
     *
     * @param bo 运维-巡检-抢修
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(OpsInspectionRepairBo bo) {
        OpsInspectionRepair add = MapstructUtils.convert(bo, OpsInspectionRepair.class);
        validEntityBeforeSave(add);

        if (add.getFileId() != null){
            String[] split = add.getFileId().split(",");
            List<String> urls = new ArrayList<>();
            for (String s : split) {
                String ossUrl = remoteFileService.selectUrlByIds(s);
                if (ossUrl != null){
                    urls.add(ossUrl);
                }
            }
            String join = String.join(",", urls);
            add.setFileUrl(join);
            bo.setFileUrl(join);
        }

        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改运维-巡检-抢修
     *
     * @param bo 运维-巡检-抢修
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(OpsInspectionRepairBo bo) {
        OpsInspectionRepair update = MapstructUtils.convert(bo, OpsInspectionRepair.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(OpsInspectionRepair entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除运维-巡检-抢修信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @GlobalTransactional
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }

        List<String> urls = new ArrayList<>();
        for (Long id : ids) {
            OpsInspectionRepairVo vo = queryById(id);
            if (vo != null){
                if (vo.getFileUrl()!=null) {
                    urls.add(vo.getFileUrl());
                }
            }
        }

        if (!urls.isEmpty()) {
            for (String url : urls) {
                List<String> list = Arrays.asList(url.split(","));
                remoteFileService.deleteFile(list);
            }
        }

        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 处理回显数据
     */
    private void setValue(List<OpsInspectionRepairVo> list){
        if (list == null || list.isEmpty()){
            return;
        }

        for (OpsInspectionRepairVo vo : list) {

            if (vo.getSendPerson() == null){
                continue;
            }

            List<RemoteUserVo> remoteUserVos = userService.selectListByIds(Collections.singletonList(vo.getSendPerson()));

            if (remoteUserVos == null || remoteUserVos.isEmpty()){
                continue;
            }

            vo.setSendPersonVo(remoteUserVos.getFirst());

            //处理分钟数
            if (vo.getStatus().equals("3")){
                long time = vo.getReportFinishTime().getTime() - vo.getCreateTime().getTime();
                vo.setMinute(String.valueOf(TimeUnit.MILLISECONDS.toMinutes( time)));
            }

            remoteUserVos = userService.selectListByIds(Collections.singletonList(vo.getCreateBy()));
            if (remoteUserVos != null&&!remoteUserVos.isEmpty()){
                if (remoteUserVos.getFirst().getUserName()!=null) {
                    vo.setName(remoteUserVos.getFirst().getUserName());
                }
                if (remoteUserVos.getFirst().getPhonenumber()!=null){
                    vo.setReportPhone(remoteUserVos.getFirst().getPhonenumber());
                }
            }

        }
    }

    public R<OpsInspectionReportRecordVo> record(Long projectId) {
        //变量初始化
        OpsInspectionReportRecordVo recordVo = new OpsInspectionReportRecordVo();
        OpsInspectionRepairBo bo = new OpsInspectionRepairBo();
        bo.setProjectId(projectId);
        //日期初始化
        LocalDate firstDay = LocalDate.now().withDayOfMonth(1);
        LocalDate lastDay = firstDay.plusMonths(1).minusDays(1);
        Date startDate = Date.from(firstDay.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(lastDay.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
        //查询当前项目的报修数据
        List<OpsInspectionRepairVo> vos = queryList(bo);

        //过滤本月数据
        List<OpsInspectionRepairVo> thisMonth = vos.stream()
            .filter(vo -> vo.getCreateTime().after(startDate))
            .filter(vo -> vo.getCreateTime().before(endDate))
            .toList();
        //本月总报修数
        recordVo.setByzbxs(String.valueOf(thisMonth.size()));

        //平均处理时长    完成时间-创建时间 转为 分钟 / 总报
        Long time = 0L;//总共完成时间
        for (OpsInspectionRepairVo vo : thisMonth) {
            if (vo.getStatus().equals("3")){
                time += vo.getReportFinishTime().getTime() - vo.getCreateTime().getTime();
            }
        }
        time = TimeUnit.MILLISECONDS.toMinutes(time);
        BigDecimal divide1 = BigDecimal.valueOf(time).divide(BigDecimal.valueOf(thisMonth.size()), 0, RoundingMode.HALF_UP);
        long hours = TimeUnit.MINUTES.toHours(Long.parseLong(divide1.toString()));

        //平均处理时长
        recordVo.setPjclsc(Long.toString(hours));

        //待处理报修
        int size = thisMonth.stream().filter(vo -> vo.getStatus().equals("1")).toList().size();
        recordVo.setDclbx(String.valueOf(size));

        //完成率
        //完成数
        int finishCount = thisMonth.stream().filter(vo -> vo.getStatus().equals("3")).toList().size();
        BigDecimal divide = BigDecimal.valueOf(finishCount).divide(BigDecimal.valueOf(thisMonth.size()), 2, RoundingMode.HALF_UP);
        recordVo.setWcl(divide.multiply(new BigDecimal("100")).toString());

        //统计上一月的数据
        firstDay = LocalDate.now().minusMonths(1).withDayOfMonth(1);
        lastDay = firstDay.plusMonths(1).minusDays(1);
        Date finalStartDate = Date.from(firstDay.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date finalEndDate = Date.from(lastDay.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());


        thisMonth = vos.stream()
            .filter(vo -> vo.getCreateTime().after(finalStartDate))
            .filter(vo -> vo.getCreateTime().before(finalEndDate))
            .toList();

        //上一月总报修数
        Long lastMonth = (long) thisMonth.size();
        //上一月平均处理时长
        BigDecimal avg;
        time = 0L;
        for (OpsInspectionRepairVo vo : thisMonth) {
            if (vo.getStatus().equals("3")){
                time += vo.getReportFinishTime().getTime() - vo.getCreateTime().getTime();
            }
        }
        time = TimeUnit.MILLISECONDS.toMinutes(time);

        if (thisMonth.isEmpty()){
            avg = BigDecimal.ZERO;
        }else {
            avg = BigDecimal.valueOf(time).divide(BigDecimal.valueOf(thisMonth.size()),2, RoundingMode.HALF_UP);
        }
        //上一月完成率
        finishCount = thisMonth.stream().filter(vo -> vo.getStatus().equals("3")).toList().size();

        if (!thisMonth.isEmpty()) {
            divide = BigDecimal.valueOf(finishCount).divide(BigDecimal.valueOf(thisMonth.size()), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
        }else {
            divide = BigDecimal.ZERO;
        }

        //总报修数增长率
        BigDecimal multiply;
        if (lastMonth != 0) {
            multiply = BigDecimal.valueOf(Long.parseLong(recordVo.getByzbxs())).divide(BigDecimal.valueOf(lastMonth), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
        }else {
            multiply = BigDecimal.ZERO;
        }
        recordVo.setBxsjszzzl(multiply.toString());

        //平均处理时长增长率 本月 / 上月 * 100
        if (!avg.equals(BigDecimal.ZERO)) {
            recordVo.setClscjszzzl(BigDecimal.valueOf(Long.parseLong(recordVo.getPjclsc())).divide(avg, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")).toString());
        }else{
            recordVo.setClscjszzzl("0");
        }

        //完成率增长率 本月 / 上月 * 100
        if (!divide.equals(BigDecimal.ZERO)) {
            recordVo.setWcljszzzl(BigDecimal.valueOf(Long.parseLong(recordVo.getWcl())).divide(divide, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")).toString());
        }else {
            recordVo.setWcljszzzl("0");
        }
        return R.ok(recordVo);
    }

}
