package com.ruoyi.system.service.fieldchangerecord.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.changerecord.enums.SubjectType;
import com.ruoyi.system.domain.fieldchangerecord.enums.FieldCode;
import com.ruoyi.system.domain.fieldchangerecord.vo.FieldChangeAffectedHouseResourceVO;
import com.ruoyi.system.domain.fieldchangerecord.vo.FieldChangeRecordQuery;
import com.ruoyi.system.domain.fieldchangerecord.vo.FieldChangeRecordVO;
import com.ruoyi.system.domain.fieldchangerecord.vo.FieldChangeSummaryRow;
import com.ruoyi.system.domain.grid.GridRegion;
import com.ruoyi.system.domain.grid.GridRegionUser;
import com.ruoyi.system.domain.grid.GridRegionUserExample;
import com.ruoyi.system.mapper.fieldchangerecord.DataFieldChangeRecordQueryMapper;
import com.ruoyi.system.mapper.grid.GridRegionMapper;
import com.ruoyi.system.mapper.grid.GridRegionUserMapper;
import com.ruoyi.system.service.fieldchangerecord.DataFieldChangeRecordService;
import com.ruoyi.system.service.house.impl.HouseResourceServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 字段级变更查询服务实现。
 *
 * <p>职责：</p>
 * <ul>
 *     <li>参数校验（时间范围必填、start &lt;= end）；</li>
 *     <li>注入登录人网格权限 {@code wgCodes}（和 HR 侧 dataCollection 一致）；</li>
 *     <li>HR / BE 字段统计接口未指定 {@code fieldCodes} 时，补齐为当前主体侧的全部字段；</li>
 *     <li>涉及房源接口只按时间、操作类型、网格过滤，不按字段过滤；</li>
 *     <li>调用 Mapper 查询；</li>
 *     <li>回填 {@code fieldLabel} / {@code valueType}（从 {@link FieldCode} 反查）。</li>
 *     <li>涉及房源分页按当前页批量回填网格名称。</li>
 * </ul>
 *
 * <p>网格权限白名单与 HR 侧 {@code dataCollection} 完全一致。为避免循环依赖，
 * 这里自己维护一份白名单 + 本地的 wgCodes 解析逻辑（和
 * {@code HouseResourceServiceImpl.resolveCurrentUserWgCodes} 对齐）。</p>
 */
@Service
public class DataFieldChangeRecordServiceImpl implements DataFieldChangeRecordService {

    private final DataFieldChangeRecordQueryMapper queryMapper;

    private final GridRegionUserMapper gridRegionUserMapper;

    private final GridRegionMapper gridRegionMapper;

    public DataFieldChangeRecordServiceImpl(DataFieldChangeRecordQueryMapper queryMapper,
                                            GridRegionUserMapper gridRegionUserMapper,
                                            GridRegionMapper gridRegionMapper) {
        this.queryMapper = queryMapper;
        this.gridRegionUserMapper = gridRegionUserMapper;
        this.gridRegionMapper = gridRegionMapper;
    }

    @Override
    public IPage<FieldChangeRecordVO> pageHouseResourceFieldChanges(FieldChangeRecordQuery query) {
        validateTimeRange(query);
        applyWgCodes(query);
        applyDefaultFieldCodes(query, SubjectType.HOUSE_RESOURCE);

        Page<FieldChangeRecordVO> page = new Page<>(
                query.getPageNum() == null ? 1 : query.getPageNum(),
                query.getPageSize() == null ? 20 : query.getPageSize());
        IPage<FieldChangeRecordVO> result = queryMapper.selectHouseResourceFieldChanges(page, query);
        enrichRecords(result.getRecords());
        return result;
    }

    @Override
    public List<FieldChangeSummaryRow> summaryHouseResourceFieldChanges(FieldChangeRecordQuery query) {
        validateTimeRange(query);
        applyWgCodes(query);
        applyDefaultFieldCodes(query, SubjectType.HOUSE_RESOURCE);
        List<FieldChangeSummaryRow> rows = queryMapper.selectHouseResourceFieldChangeSummary(query);
        enrichSummary(rows);
        return rows;
    }

    @Override
    public IPage<FieldChangeRecordVO> pageBusinessEntityFieldChanges(FieldChangeRecordQuery query) {
        validateTimeRange(query);
        applyWgCodes(query);
        applyDefaultFieldCodes(query, SubjectType.BUSINESS_ENTITY_INFO);

        Page<FieldChangeRecordVO> page = new Page<>(
                query.getPageNum() == null ? 1 : query.getPageNum(),
                query.getPageSize() == null ? 20 : query.getPageSize());
        IPage<FieldChangeRecordVO> result = queryMapper.selectBusinessEntityFieldChanges(page, query);
        enrichRecords(result.getRecords());
        return result;
    }

    @Override
    public List<FieldChangeSummaryRow> summaryBusinessEntityFieldChanges(FieldChangeRecordQuery query) {
        validateTimeRange(query);
        applyWgCodes(query);
        applyDefaultFieldCodes(query, SubjectType.BUSINESS_ENTITY_INFO);
        List<FieldChangeSummaryRow> rows = queryMapper.selectBusinessEntityFieldChangeSummary(query);
        enrichSummary(rows);
        return rows;
    }

    @Override
    public IPage<FieldChangeAffectedHouseResourceVO> pageAffectedHouseResources(FieldChangeRecordQuery query) {
        validateTimeRange(query);
        applyWgCodes(query);

        Page<FieldChangeAffectedHouseResourceVO> page = new Page<>(
                query.getPageNum() == null ? 1 : query.getPageNum(),
                query.getPageSize() == null ? 20 : query.getPageSize());
        IPage<FieldChangeAffectedHouseResourceVO> result = queryMapper.selectAffectedHouseResources(page, query);
        enrichAffectedHouseResourceGridNames(result.getRecords());
        return result;
    }

    @Override
    public List<FieldChangeSummaryRow> summaryAffectedHouseResources(FieldChangeRecordQuery query) {
        validateTimeRange(query);
        applyWgCodes(query);
        return queryMapper.selectAffectedHouseResourceSummary(query);
    }

    // -------------------------------------------------------------------------

    private void validateTimeRange(FieldChangeRecordQuery query) {
        if (query.getChangeStartTime() == null || query.getChangeEndTime() == null) {
            throw new IllegalArgumentException("changeStartTime / changeEndTime 必填");
        }
        if (query.getChangeStartTime().after(query.getChangeEndTime())) {
            throw new IllegalArgumentException("changeStartTime 不能晚于 changeEndTime");
        }
    }

    private void applyWgCodes(FieldChangeRecordQuery query) {
        List<String> wgCodes = resolveCurrentUserWgCodes();
        if (wgCodes != null) {
            query.setWgCodes(wgCodes);
        }
    }

    /**
     * 与 {@code HouseResourceServiceImpl.resolveCurrentUserWgCodes(true)} 行为一致。
     */
    private List<String> resolveCurrentUserWgCodes() {
        String userId = SecurityUtils.getLoginUser().getUser().getUserId();
        GridRegionUserExample example = new GridRegionUserExample();
        example.createCriteria().andIsValidEqualTo("1").andUserIdEqualTo(userId);
        List<GridRegionUser> gridRegionUsers = gridRegionUserMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(gridRegionUsers) || SecurityUtils.getLoginUser().getUser().isAdmin()) {
            return null;
        }
        if (HouseResourceServiceImpl.WG_PERMISSION_BYPASS_USER_IDS.contains(userId)) {
            return null;
        }
        return gridRegionUsers.stream().map(GridRegionUser::getWgId).collect(Collectors.toList());
    }

    /**
     * 若入参没指定 fieldCodes，则按主体侧默认补齐全部字段。
     * 若指定了 fieldCodes，按入参原样使用（后端不做属于哪个主体的校验——前端分 tab 自然不会传错）。
     */
    private void applyDefaultFieldCodes(FieldChangeRecordQuery query, SubjectType subjectType) {
        if (query.getFieldCodes() == null || query.getFieldCodes().isEmpty()) {
            List<String> defaults = Arrays.stream(FieldCode.values())
                    .filter(f -> f.getSubjectType() == subjectType)
                    .map(Enum::name)
                    .collect(Collectors.toList());
            query.setFieldCodes(defaults);
        }
    }

    private void enrichRecords(List<FieldChangeRecordVO> list) {
        if (list == null) {
            return;
        }
        for (FieldChangeRecordVO vo : list) {
            FieldCode fc = FieldCode.fromCode(vo.getFieldCode());
            if (fc != null) {
                vo.setFieldLabel(fc.getLabel());
                vo.setValueType(fc.getValueType().name());
            }
        }
    }

    private void enrichSummary(List<FieldChangeSummaryRow> list) {
        if (list == null) {
            return;
        }
        for (FieldChangeSummaryRow row : list) {
            FieldCode fc = FieldCode.fromCode(row.getFieldCode());
            if (fc != null) {
                row.setFieldLabel(fc.getLabel());
                row.setValueType(fc.getValueType().name());
            }
        }
    }

    private void enrichAffectedHouseResourceGridNames(List<FieldChangeAffectedHouseResourceVO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Set<String> codes = new HashSet<>();
        for (FieldChangeAffectedHouseResourceVO vo : list) {
            addGridCode(codes, vo.getTwo());
            addGridCode(codes, vo.getThree());
            addGridCode(codes, vo.getFour());
        }
        if (codes.isEmpty()) {
            return;
        }
        List<GridRegion> regions = gridRegionMapper.selectByCodes(codes);
        if (CollectionUtils.isEmpty(regions)) {
            return;
        }
        Map<String, String> nameByCode = regions.stream()
                .filter(r -> r.getWgCode() != null && r.getWgName() != null)
                .collect(Collectors.toMap(
                        GridRegion::getWgCode,
                        GridRegion::getWgName,
                        (oldValue, newValue) -> oldValue));
        for (FieldChangeAffectedHouseResourceVO vo : list) {
            vo.setWgName2(nameByCode.get(vo.getTwo()));
            vo.setWgName3(nameByCode.get(vo.getThree()));
            vo.setWgName4(nameByCode.get(vo.getFour()));
        }
    }

    private void addGridCode(Set<String> codes, String code) {
        if (code != null && !code.isEmpty()) {
            codes.add(code);
        }
    }
}
