package com.zcloud.personnel.positioning.command.query;

import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jjb.saas.framework.auth.model.SSOUser;
import com.jjb.saas.framework.auth.utils.AuthContext;
import com.zcloud.personnel.positioning.command.convertor.AlarmRecordCoConvertor;
import com.zcloud.personnel.positioning.command.convertor.AlarmRecordTargetCoConvertor;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiAlarmTypeQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordBiQry;
import com.zcloud.personnel.positioning.dto.AlarmRecordPageQry;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmTypeStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.AlarmRecordTargetCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmTypeStatDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordDO;
import com.zcloud.personnel.positioning.persistence.dataobject.AlarmRecordTargetDO;
import com.zcloud.personnel.positioning.persistence.repository.AlarmRecordRepository;
import com.zcloud.personnel.positioning.persistence.repository.AlarmRecordTargetRepository;
import lombok.AllArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Alarm record query executor.
 *
 * @Author fangjiakai
 * @Date 2026-07-07
 */
@Component
@AllArgsConstructor
public class AlarmRecordQueryExe {
    private final AlarmRecordRepository alarmRecordRepository;
    private final AlarmRecordTargetRepository alarmRecordTargetRepository;
    private final AlarmRecordCoConvertor alarmRecordCoConvertor;
    private final AlarmRecordTargetCoConvertor alarmRecordTargetCoConvertor;
    private final JdbcTemplate jdbcTemplate;

    public PageResponse<AlarmRecordCO> execute(AlarmRecordPageQry qry) {
        AlarmRecordPageQry query = qry == null ? new AlarmRecordPageQry() : qry;
        normalizeQuery(query);
        Map<String, Object> params = query.toHashMap();
        normalizeParams(params);
        fillCorpinfo(params);
        params.put("eqDeleteEnum", "FALSE");
        PageResponse<AlarmRecordDO> pageResponse = alarmRecordRepository.listPage(params);
        List<AlarmRecordCO> data = alarmRecordCoConvertor.converDOsToCOs(pageResponse.getData());
        fillTargetsAndDisplayFields(data);
        return PageResponse.of(data, pageResponse.getTotalCount(), pageResponse.getPageSize(), pageResponse.getPageIndex());
    }

    public List<AlarmRecordCO> listBiAlarm(AlarmRecordBiQry qry) {
        AlarmRecordBiQry query = qry == null ? new AlarmRecordBiQry() : qry;
        String corpinfoId = query.getCorpinfoId() == null ? null : String.valueOf(query.getCorpinfoId());
        List<AlarmRecordCO> rows = alarmRecordCoConvertor.converDOsToCOs(
                alarmRecordRepository.listBiAlarm(corpinfoId, query.getPortArea()));
        return rows;
    }

    public List<AlarmTypeStatCO> listBiAlarmType(AlarmRecordBiAlarmTypeQry qry) {
        AlarmRecordBiAlarmTypeQry query = qry == null ? new AlarmRecordBiAlarmTypeQry() : qry;
        String corpinfoId = query.getCorpinfoId() == null ? null : String.valueOf(query.getCorpinfoId());
        List<AlarmTypeStatDO> rows = alarmRecordRepository.listBiAlarmType(corpinfoId);
        if (rows == null || rows.isEmpty()) {
            return Collections.emptyList();
        }
        List<AlarmTypeStatCO> result = new ArrayList<>();
        for (AlarmTypeStatDO row : rows) {
            if (row == null) {
                continue;
            }
            AlarmTypeStatCO co = new AlarmTypeStatCO();
            co.setAlarmCode(row.getAlarmCode());
            co.setAlarmName(alarmTypeNameOf(row.getAlarmCode(), row.getAlarmName()));
            co.setAlarmCount(row.getAlarmCount());
            result.add(co);
        }
        return result;
    }

    public List<AlarmRecordCO> listAll() {
        QueryWrapper<AlarmRecordDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("delete_enum", "FALSE");
        applyCorpinfo(queryWrapper);
        queryWrapper.orderByDesc("start_time", "create_time");
        List<AlarmRecordCO> rows = alarmRecordCoConvertor.converDOsToCOs(alarmRecordRepository.list(queryWrapper));
        fillTargetsAndDisplayFields(rows);
        return rows;
    }

    public AlarmRecordCO queryById(Long id) {
        QueryWrapper<AlarmRecordDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        queryWrapper.eq("delete_enum", "FALSE");
        applyCorpinfo(queryWrapper);
        AlarmRecordDO dataObject = alarmRecordRepository.getOne(queryWrapper, false);
        AlarmRecordCO co = alarmRecordCoConvertor.converDOToCO(dataObject);
        if (co == null) {
            return null;
        }
        fillTargetsAndDisplayFields(Collections.singletonList(co));
        return co;
    }

    public List<OptionCO> listCompanyOptions() {
        List<Object> args = new ArrayList<>();
        StringBuilder sql = new StringBuilder("SELECT corpinfo_id, corp_name FROM corp_info "
                + "WHERE (delete_enum IS NULL OR delete_enum = 'FALSE') "
                + "AND corpinfo_id IS NOT NULL AND corp_name IS NOT NULL");
        SSOUser ssoUser = AuthContext.getCurrentUser();
        if (ssoUser != null && ssoUser.getCompanyId() != null) {
            sql.append(" AND corpinfo_id = ?");
            args.add(String.valueOf(ssoUser.getCompanyId()));
        }
        sql.append(" ORDER BY corp_name ASC LIMIT 200");
        return jdbcTemplate.query(sql.toString(), args.toArray(), this::mapCompanyOption);
    }

    public List<OptionCO> listAlarmTypeOptions() {
        return Arrays.asList(
                new OptionCO("禁入围栏告警", "CROSS_IN"),
                new OptionCO("离开围栏告警", "CROSS_OUT"),
                new OptionCO("超时停留告警", "RETENTION"),
                new OptionCO("脱岗告警", "LACKED"),
                new OptionCO("停留告警", "STAY"),
                new OptionCO("聚集告警", "CLUSTER"),
                new OptionCO("超员告警", "CROWDED"),
                new OptionCO("静止告警", "STATIC"),
                new OptionCO("超速告警", "OVER_SPEED"),
                new OptionCO("碰撞告警", "CRASH"),
                new OptionCO("低电量告警", "LOW_BATTERY"),
                new OptionCO("SOS告警", "SOS")
        );
    }

    private OptionCO mapCompanyOption(ResultSet rs, int rowNum) throws SQLException {
        String corpinfoId = rs.getString("corpinfo_id");
        return new OptionCO(rs.getString("corp_name"), corpinfoId);
    }

    private void fillTargetsAndDisplayFields(List<AlarmRecordCO> rows) {
        if (rows == null || rows.isEmpty()) {
            return;
        }
        Map<Long, List<AlarmRecordTargetCO>> targetMap = queryTargetMap(rows);
        for (AlarmRecordCO row : rows) {
            List<AlarmRecordTargetCO> targetList = targetMap.getOrDefault(row.getId(), Collections.emptyList());
            row.setTargetList(targetList);
            row.setPersonnelName(defaultIfBlank(row.getFirstStaffNameSnapshot(), firstTargetName(targetList)));
            row.setCompanyName(row.getCorpinfoName());
            row.setAlarmTypeName(defaultIfBlank(row.getAlarmName(), alarmNameOf(row.getAlarmCode())));
        }
    }

    private Map<Long, List<AlarmRecordTargetCO>> queryTargetMap(List<AlarmRecordCO> rows) {
        List<Long> recordIds = rows.stream()
                .map(AlarmRecordCO::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (recordIds.isEmpty()) {
            return Collections.emptyMap();
        }
        QueryWrapper<AlarmRecordTargetDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("alarm_record_id", recordIds);
        queryWrapper.eq("delete_enum", "FALSE");
        queryWrapper.orderByAsc("id");
        List<AlarmRecordTargetCO> targets = alarmRecordTargetCoConvertor
                .converDOsToCOs(alarmRecordTargetRepository.list(queryWrapper));
        if (targets == null || targets.isEmpty()) {
            return Collections.emptyMap();
        }
        return targets.stream().collect(Collectors.groupingBy(AlarmRecordTargetCO::getAlarmRecordId,
                LinkedHashMap::new, Collectors.toList()));
    }

    private String firstTargetName(List<AlarmRecordTargetCO> targetList) {
        if (targetList == null) {
            return null;
        }
        for (AlarmRecordTargetCO target : targetList) {
            if (StringUtils.hasText(target.getTrackName())) {
                return target.getTrackName();
            }
        }
        return null;
    }

    private void normalizeQuery(AlarmRecordPageQry query) {
        query.setEqAlarmCode(normalizeAlarmCode(query.getEqAlarmCode()));
    }

    private void normalizeParams(Map<String, Object> params) {
        params.put("eqAlarmCode", normalizeAlarmCode((String) params.get("eqAlarmCode")));
        Object orgName = params.get("likeOrgName");
        if (!StringUtils.hasText((String) params.get("likeCorpinfoName")) && orgName instanceof String
                && StringUtils.hasText((String) orgName)) {
            params.put("likeCorpinfoName", orgName);
        }
        params.remove("eqOrgCode");
        params.remove("likeOrgName");
    }

    private void fillCorpinfo(Map<String, Object> params) {
        if (params.get("eqCorpinfoId") != null || StringUtils.hasText((String) params.get("likeCorpinfoName"))) {
            return;
        }
        SSOUser ssoUser = AuthContext.getCurrentUser();
        if (ssoUser != null && ssoUser.getCompanyId() != null) {
            params.put("eqCorpinfoId", String.valueOf(ssoUser.getCompanyId()));
        }
    }

    private void applyCorpinfo(QueryWrapper<AlarmRecordDO> queryWrapper) {
        SSOUser ssoUser = AuthContext.getCurrentUser();
        if (ssoUser != null && ssoUser.getCompanyId() != null) {
            queryWrapper.eq("corpinfo_id", String.valueOf(ssoUser.getCompanyId()));
        }
    }


    private String normalizeAlarmCode(String value) {
        if (!StringUtils.hasText(value)) {
            return null;
        }
        String code = value.trim();
        if ("进入围栏告警".equals(code) || "禁入围栏告警".equals(code)) {
            return "CROSS_IN";
        }
        if ("离开围栏".equals(code) || "离开围栏告警".equals(code) || "区域越界告警".equals(code)) {
            return "CROSS_OUT";
        }
        if ("超时停留告警".equals(code)) {
            return "RETENTION";
        }
        if ("脱岗告警".equals(code)) {
            return "LACKED";
        }
        if ("停留告警".equals(code)) {
            return "STAY";
        }
        if ("聚集告警".equals(code)) {
            return "CLUSTER";
        }
        if ("超员告警".equals(code)) {
            return "CROWDED";
        }
        if ("静止告警".equals(code)) {
            return "STATIC";
        }
        if ("超速告警".equals(code)) {
            return "OVER_SPEED";
        }
        if ("碰撞告警".equals(code)) {
            return "CRASH";
        }
        if ("低电量告警".equals(code)) {
            return "LOW_BATTERY";
        }
        if ("SOS告警".equalsIgnoreCase(code)) {
            return "SOS";
        }
        return code;
    }

    private String alarmNameOf(String alarmCode) {
        if ("CROSS_IN".equals(alarmCode)) {
            return "禁入围栏告警";
        }
        if ("CROSS_OUT".equals(alarmCode)) {
            return "离开围栏告警";
        }
        if ("RETENTION".equals(alarmCode)) {
            return "超时停留告警";
        }
        if ("LACKED".equals(alarmCode)) {
            return "脱岗告警";
        }
        if ("STAY".equals(alarmCode)) {
            return "停留告警";
        }
        if ("CLUSTER".equals(alarmCode)) {
            return "聚集告警";
        }
        if ("CROWDED".equals(alarmCode)) {
            return "超员告警";
        }
        if ("STATIC".equals(alarmCode)) {
            return "静止告警";
        }
        if ("OVER_SPEED".equals(alarmCode)) {
            return "超速告警";
        }
        if ("CRASH".equals(alarmCode)) {
            return "碰撞告警";
        }
        if ("LOW_BATTERY".equals(alarmCode)) {
            return "低电量告警";
        }
        if ("SOS".equals(alarmCode)) {
            return "SOS告警";
        }
        return alarmCode;
    }

    private String alarmTypeNameOf(String alarmCode, String alarmName) {
        String name = defaultIfBlank(alarmName, alarmNameOf(alarmCode));
        if (name != null && name.contains("-")) {
            return name.substring(name.lastIndexOf('-') + 1);
        }
        return name;
    }

    private String defaultIfBlank(String value, String defaultValue) {
        return StringUtils.hasText(value) ? value : defaultValue;
    }

}
