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

import com.alibaba.cola.dto.PageResponse;
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.AlarmRuleConfigPersistence;
import com.zcloud.personnel.positioning.command.FencePersistenceSupport;
import com.zcloud.personnel.positioning.command.convertor.FenceCoConvertor;
import com.zcloud.personnel.positioning.dto.FenceCompanyPageQry;
import com.zcloud.personnel.positioning.dto.FencePageQry;
import com.zcloud.personnel.positioning.dto.clientobject.FenceCO;
import com.zcloud.personnel.positioning.dto.clientobject.FenceCompanyStatCO;
import com.zcloud.personnel.positioning.dto.clientobject.OptionCO;
import com.zcloud.personnel.positioning.persistence.dataobject.FenceDO;
import com.zcloud.personnel.positioning.persistence.repository.FenceRepository;
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.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
@AllArgsConstructor
public class FenceQueryExe {
    private final FenceRepository fenceRepository;
    private final FenceCoConvertor fenceCoConvertor;
    private final JdbcTemplate jdbcTemplate;

    public List<OptionCO> listCompanyOptions(String keyword) {
        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()));
        }
        if (StringUtils.hasText(keyword)) {
            sql.append(" AND (corp_name LIKE ? OR code LIKE ? OR contacts LIKE ? OR lr_name LIKE ?)");
            String value = "%" + keyword.trim() + "%";
            args.add(value);
            args.add(value);
            args.add(value);
            args.add(value);
        }
        sql.append(" ORDER BY corp_name ASC LIMIT 200");
        return jdbcTemplate.query(sql.toString(), args.toArray(), this::mapCompanyOption);
    }

    public PageResponse<FenceCompanyStatCO> listCompanyStats(FenceCompanyPageQry qry) {
        FenceCompanyPageQry query = qry == null ? new FenceCompanyPageQry() : qry;
        int pageIndex = normalizePageIndex(query.getPageIndex());
        int pageSize = normalizePageSize(query.getPageSize());
        int offset = (pageIndex - 1) * pageSize;

        List<Object> args = new ArrayList<>();
        String fromWhere = buildCompanyStatsFromWhere(query, args);
        String groupKey = "COALESCE(CAST(corpinfo_id AS CHAR), NULLIF(corpinfo_name, ''), 'UNKNOWN')";
        String countSql = "SELECT COUNT(1) FROM (SELECT " + groupKey + " AS company_key "
                + fromWhere + " GROUP BY company_key) t";
        Long total = jdbcTemplate.queryForObject(countSql, args.toArray(), Long.class);

        String dataSql = "SELECT MIN(corpinfo_id) AS corpinfo_id, "
                + "COALESCE(MAX(NULLIF(corpinfo_name, '')), 'UNKNOWN') AS corpinfo_name, "
                + "COUNT(1) AS fence_count, "
                + "SUM(CASE WHEN status = 'ENABLED' THEN 1 ELSE 0 END) AS enabled_count, "
                + "COALESCE(MAX(last_sync_time), MAX(update_time)) AS last_sync_time "
                + fromWhere
                + " GROUP BY " + groupKey
                + " ORDER BY COALESCE(MAX(last_sync_time), MAX(update_time)) DESC"
                + " LIMIT ? OFFSET ?";
        List<Object> dataArgs = new ArrayList<>(args);
        dataArgs.add(pageSize);
        dataArgs.add(offset);
        List<FenceCompanyStatCO> rows = jdbcTemplate.query(dataSql, dataArgs.toArray(), this::mapCompanyStat);
        return PageResponse.of(rows, total == null ? 0 : total.intValue(), pageSize, pageIndex);
    }

    public PageResponse<FenceCO> execute(FencePageQry qry) {
        FencePageQry query = qry == null ? new FencePageQry() : qry;
        Map<String, Object> params = query.toHashMap();
        params.put("eqDeleteEnum", "FALSE");
        if (!StringUtils.hasText((String) params.get("eqFenceScope"))) {
            params.put("excludeCompanyArea", Boolean.TRUE);
        }
        normalizeListParams(params);
        fillCorpinfo(params);
        prepareCorpinfoFallback(params);
        PageResponse<FenceDO> pageResponse = fenceRepository.listPage(params);
        List<FenceCO> data = fenceCoConvertor.converDOsToCOs(pageResponse.getData());
        return PageResponse.of(data, pageResponse.getTotalCount(), pageResponse.getPageSize(), pageResponse.getPageIndex());
    }

    public List<FenceCO> listAll() {
        QueryWrapper<FenceDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("delete_enum", "FALSE");
        queryWrapper.ne("fence_scope", FencePersistenceSupport.SCOPE_COMPANY_AREA);
        applyCorpinfo(queryWrapper);
        queryWrapper.orderByDesc("create_time");
        return fenceCoConvertor.converDOsToCOs(fenceRepository.list(queryWrapper));
    }

    public FenceCO queryById(Long id) {
        QueryWrapper<FenceDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        queryWrapper.eq("delete_enum", "FALSE");
        FenceDO dataObject = fenceRepository.getOne(queryWrapper, false);
        return fenceCoConvertor.converDOToCO(dataObject);
    }

    private String buildCompanyStatsFromWhere(FenceCompanyPageQry qry, List<Object> args) {
        StringBuilder sql = new StringBuilder("FROM fence WHERE (delete_enum IS NULL OR delete_enum = 'FALSE')")
                .append(" AND fence_scope IN ('")
                .append(FencePersistenceSupport.SCOPE_ELECTRONIC)
                .append("','")
                .append(FencePersistenceSupport.SCOPE_WORK_AREA)
                .append("')");
        if (qry.getEqCorpinfoId() != null) {
            sql.append(" AND corpinfo_id = ?");
            args.add(qry.getEqCorpinfoId());
        }
        if (StringUtils.hasText(qry.getLikeCorpinfoName())) {
            sql.append(" AND corpinfo_name LIKE ?");
            args.add("%" + qry.getLikeCorpinfoName().trim() + "%");
        }
        return sql.toString();
    }

    private FenceCompanyStatCO mapCompanyStat(ResultSet rs, int rowNum) throws SQLException {
        FenceCompanyStatCO co = new FenceCompanyStatCO();
        String corpinfoId = rs.getString("corpinfo_id");
        co.setCorpinfoId(rs.wasNull() ? null : corpinfoId);
        co.setCorpinfoName(rs.getString("corpinfo_name"));
        co.setFenceCount(rs.getInt("fence_count"));
        co.setEnabledCount(rs.getInt("enabled_count"));
        Timestamp lastSyncTime = rs.getTimestamp("last_sync_time");
        co.setLastSyncTime(lastSyncTime == null ? null : lastSyncTime.toLocalDateTime());
        return co;
    }

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

    private void fillCorpinfo(Map<String, Object> params) {
        if (params.get("eqCorpinfoId") != null
                || StringUtils.hasText((String) params.get("eqCorpinfoName"))
                || 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 prepareCorpinfoFallback(Map<String, Object> params) {
        String corpinfoId = (String) params.get("eqCorpinfoId");
        String corpinfoName = (String) params.get("eqCorpinfoName");
        if (corpinfoId == null || !StringUtils.hasText(corpinfoName)) {
            return;
        }
        params.remove("eqCorpinfoId");
        params.remove("eqCorpinfoName");
        params.put("corpinfoMatchId", corpinfoId);
        params.put("corpinfoMatchName", corpinfoName.trim());
    }

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

    private void normalizeListParams(Map<String, Object> params) {
        String status = normalizeStatus((String) params.get("eqStatus"));
        if (StringUtils.hasText(status)) {
            params.put("eqStatus", status);
        }
    }

    private String normalizeStatus(String status) {
        if (!StringUtils.hasText(status)) {
            return null;
        }
        String value = status.trim();
        if ("1".equals(value) || "\u542f\u7528".equals(value)) {
            return AlarmRuleConfigPersistence.STATUS_ENABLED;
        }
        if ("0".equals(value) || "\u505c\u7528".equals(value)) {
            return AlarmRuleConfigPersistence.STATUS_DISABLED;
        }
        return value;
    }

    private int normalizePageIndex(Integer pageIndex) {
        return pageIndex == null || pageIndex < 1 ? 1 : pageIndex;
    }

    private int normalizePageSize(Integer pageSize) {
        return pageSize == null || pageSize < 1 ? 20 : pageSize;
    }
}
