package com.zcloud.personnel.positioning.command;

import com.zcloud.personnel.positioning.persistence.dataobject.CorpInfoSnapshotDO;
import com.zcloud.personnel.positioning.persistence.repository.PersonnelMatchRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/** Resolves the local company of a FindS person or terminal without guessing on ambiguous data. */
@Component
@RequiredArgsConstructor
public class FindsPersonCorpResolver {
    private final PersonnelMatchRepository personnelMatchRepository;

    public FindsCorpMappingService.CorpMatch resolve(String idCardNo, String staffNo,
                                                     String staffName, String terminalNo) {
        Resolution resolution = queryMatched("idCardNo", idCardNo);
        if (!resolution.decisive) {
            resolution = queryMatched("staffNo", staffNo);
        }
        if (!resolution.decisive) {
            resolution = queryMatched("staffName", staffName);
        }
        if (!resolution.decisive) {
            resolution = queryLocal("idCardNo", idCardNo);
        }
        if (!resolution.decisive) {
            resolution = queryLocal("staffNo", staffNo);
        }
        if (!resolution.decisive) {
            resolution = queryLocal("staffName", staffName);
        }
        if (!resolution.decisive && StringUtils.hasText(terminalNo)) {
            resolution = resolveRows(personnelMatchRepository.listTerminalCompanies(terminalNo.trim()), "TERMINAL");
        }
        return resolution.match;
    }

    private Resolution queryMatched(String key, String value) {
        if (!StringUtils.hasText(value)) {
            return Resolution.notFound();
        }
        Map<String, Object> params = new LinkedHashMap<>();
        params.put(key, value.trim());
        return resolveRows(personnelMatchRepository.listMatchedPersonCompanies(params), "PERSONNEL_MATCH");
    }

    private Resolution queryLocal(String key, String value) {
        if (!StringUtils.hasText(value)) {
            return Resolution.notFound();
        }
        Map<String, Object> params = new LinkedHashMap<>();
        params.put(key, value.trim());
        return resolveRows(personnelMatchRepository.listLocalPersonCompanies(params), "LOCAL_PERSON");
    }

    private Resolution resolveRows(List<CorpInfoSnapshotDO> rows, String matchType) {
        Map<String, CorpInfoSnapshotDO> distinct = new LinkedHashMap<>();
        for (CorpInfoSnapshotDO row : rows) {
            if (row != null && StringUtils.hasText(row.getCorpinfoId())) {
                distinct.putIfAbsent(row.getCorpinfoId(), row);
            }
        }
        if (distinct.isEmpty()) {
            return Resolution.notFound();
        }
        if (distinct.size() > 1) {
            return Resolution.ambiguous();
        }
        CorpInfoSnapshotDO row = distinct.values().iterator().next();
        return Resolution.matched(new FindsCorpMappingService.CorpMatch(
                row.getCorpinfoId(), row.getCorpName(), null, null, matchType));
    }

    private static class Resolution {
        private final boolean decisive;
        private final FindsCorpMappingService.CorpMatch match;

        private Resolution(boolean decisive, FindsCorpMappingService.CorpMatch match) {
            this.decisive = decisive;
            this.match = match;
        }

        private static Resolution notFound() {
            return new Resolution(false, null);
        }

        private static Resolution ambiguous() {
            return new Resolution(true, null);
        }

        private static Resolution matched(FindsCorpMappingService.CorpMatch match) {
            return new Resolution(true, match);
        }
    }
}
