package ru.nbch.credit_tracker.service.indic;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.mapper.indic.PersonMapper;

import java.time.LocalDate;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PersonService {

    private final PersonMapper mapper;

    public PersonService(PersonMapper mapper) {
        this.mapper = mapper;
    }

    public Map<Integer, PersonData> findPersonData(List<Integer> fids) {
        if (fids.isEmpty()) {
            return new HashMap<>();
        }
        Map<Integer, PersonData> personDataMap = new HashMap<>();
        Map<Integer, NameData> nameDataMap = findNameData(fids);
        Map<Integer, PassportData> passortDataMap = findPassportData(fids);


        fids.forEach(fid -> {
            NameData person = nameDataMap.get(fid);
            PassportData passort = passortDataMap.get(fid);
            if (person != null && passort != null && requiredFieldPresent(person, passort)) {
                personDataMap.put(fid, new PersonData(person, passort));
            } else {
                log.warn("Person does not have required fields. Fid {}", fid);
            }
        });

        return personDataMap;
    }


    private Map<Integer, NameData> findNameData(List<Integer> fids) {
        List<NameData> persons = mapper.findNameData(fids);
        return persons.stream()
                .collect(Collectors.toMap(NameData::getFid, nameData -> nameData,
                        (existing, replacement) -> {
                            LocalDate existingDate = existing.getFileSinceDate();
                            LocalDate replacementDate = replacement.getFileSinceDate();
                            if (existingDate != null && replacementDate != null) {
                                if (existingDate.isAfter(replacementDate)) {
                                    return existing;
                                } else {
                                    return replacement;
                                }
                            } else if (existingDate != null) {
                                return existing;
                            } else {
                                return replacement;
                            }
                        }));
    }

    private Map<Integer, PassportData> findPassportData(List<Integer> fids) {
        Map<Integer, PassportData> resultMap = new HashMap<>();

        List<PassportData> passports = mapper.findPassportData(fids);

        Map<Integer, List<PassportData>> passportsMap = passports.stream()
                .collect(Collectors.groupingBy(PassportData::getFid));

        fids.forEach(fid -> {
            PassportData passport = findPassport(passportsMap.get(fid));
            if (passport != null) {
                resultMap.put(fid, passport);
            }
        });

        return resultMap;
    }

    private PassportData findPassport(List<PassportData> passports) {
        if (passports == null || passports.isEmpty()) {
            return null;
        }
        List<PassportData> documents = passports.stream()
                .filter(this::isDUL)
                .toList(); // берем только ДУЛ

        if (documents.isEmpty()) {
            return null;
        }

        // Отдаем приоритет паспортам РФ
        PassportData passport = documents.stream()
                .filter(p -> "21".equals(p.getIdType2()) || "21".equals(p.getIdType()))
                .sorted(
                        Comparator.comparing(
                                PassportData::getIssDate,
                                Comparator.nullsLast(Comparator.reverseOrder())
                        ).thenComparing(
                                PassportData::getFileSinceDate,
                                Comparator.nullsLast(Comparator.reverseOrder())
                        )
                ).findFirst().orElse(null);

        if (passport != null) {
            return passport;
        }

        // Если паспорт РФ не найден, смотри остальные ДУЛ'ы и берем первый
        passport = documents.stream()
                .sorted(
                        Comparator.comparing(
                                PassportData::getIssDate,
                                Comparator.nullsLast(Comparator.reverseOrder())
                        ).thenComparing(
                                PassportData::getFileSinceDate,
                                Comparator.nullsLast(Comparator.reverseOrder())
                        )
                ).findFirst().orElse(null);
        return passport;
    }

    private boolean isDUL(PassportData p) {
        Integer idType;
        Double idType2;
        try {
            idType = p.getIdType() != null ? Integer.parseInt(p.getIdType()) : null;
        } catch (NumberFormatException e) {
            idType = null;
        }
        try {
            idType2 = p.getIdType2() != null ? Double.valueOf(p.getIdType2()) : null;
        } catch (NumberFormatException e) {
            idType2 = null;
        }
        return (idType != null && idType <= 30 && idType != 12) || (idType2 != null && (idType2 >= 1 || idType2 <= 999));
    }

    private boolean requiredFieldPresent(NameData nameData, PassportData passportData) {
        boolean isDocTypeNotNull = StringUtils.isNotBlank(passportData.idType) || StringUtils.isNotBlank(passportData.idType2);
        return !StringUtils.isAllBlank(nameData.firstName, nameData.lastName, passportData.idNum) && nameData.birthDate != null && isDocTypeNotNull;
    }

    @Getter
    @AllArgsConstructor
    public static class PersonData {
        private NameData name;
        private PassportData passport;
    }

    @Getter
    @Setter
    public static class NameData {
        private Integer fid;
        private String firstName;
        private String lastName;
        private String middleName;
        private LocalDate birthDate;
        private LocalDate fileSinceDate;
    }

    @Getter
    @Setter
    public static class PassportData {
        private Integer fid;
        private String serNum;
        private String idNum;
        private LocalDate issDate;
        private String idType;
        private String idType2;
        private LocalDate fileSinceDate;
    }
}
