package com.ruoyi.common.utils;

import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.business.domain.TbArea;
import com.ruoyi.project.business.domain.TbCountry;
import com.ruoyi.project.business.domain.TpParaLibrary;
import com.ruoyi.project.business.domain.TpParaSelectItem;
import com.ruoyi.project.business.service.ITbAreaService;
import com.ruoyi.project.business.service.ITbCountryService;
import com.ruoyi.project.system.domain.SysDictData;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.util.Pair;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static com.ruoyi.common.constant.Constants.*;


/**
 * @author fangk
 * @date 2024/5/29
 * @desc LocalUtils 本地化获取区域、国家 getter 工具类
 */
public class LocalUtils {

    private static final Supplier<String> LOCAL = () -> {
        try {
            return LocaleContextHolder.getLocale().getCountry();
        } catch (Exception e) {
            return "";
        }
    };

    public static Function<TbArea, String> localAreaNameFun() {
        return AREA_LOCAL_NAME_FUN.getOrDefault(LOCAL.get(), TbArea::getAreaName);
    }

    public static Function<TbCountry, String> localCountryNameFun() {
        return COUNTRY_LOCAL_NAME_FUN.getOrDefault(LOCAL.get(), TbCountry::getCountryName);
    }

    public static Function<TpParaLibrary, String> localParaNameFun(String country) {
        return PARA_LOCAL_NAME_FUN.getOrDefault(StringUtils.isNotBlank(country) ? country: LOCAL.get(), TpParaLibrary::getParaName);
    }

    public static Function<TpParaLibrary, String> localParaNameFun() {
        return LocalUtils.localParaNameFun(null);
    }

    public static Function<TpParaSelectItem, String> localParaItemNameFun(String country) {
        return PARA_ITEM_LOCAL_NAME_FUN.getOrDefault(StringUtils.isNotBlank(country) ? country: LOCAL.get(), TpParaSelectItem::getLabel);
    }

    public static Function<TpParaSelectItem, String> localParaItemNameFun() {
        return LocalUtils.localParaItemNameFun(null);
    }
    
    public static Function<SysDictData, String> localDictLabelFun(String country) {
        return DICT_LOCAL_LABEL_FUN.getOrDefault(StringUtils.isNotBlank(country) ? country: LOCAL.get(), SysDictData::getDictLabel);
    }

    public static Function<SysDictData, String> localDictLabelFun() {
        return LocalUtils.localDictLabelFun(null);
    }

    // TODO 这些方法改为注解实现（注解带方法引用的话，需要实现Serializable接口处理泛型）

    /**
     * 设置本地化区域名称
     *
     * @param t          操作对象
     * @param idGetter   获取区域id的方法
     * @param nameSetter 设置区域名称的方法
     * @param <T>        操作对象类型
     */
    public static <T> void setLocalAreaName(T t, Function<T, Long> idGetter, BiConsumer<T, String> nameSetter) {
        // 获取 areaId 值
        Long idValue = idGetter.apply(t);

        // 处理id值（假设处理逻辑是将id值转换为name）
        String localName = getLocalAreaName(idValue);

        // 设置 areaName 值
        nameSetter.accept(t, localName);
    }

    /**
     * 获取本地化区域名称
     *
     * @param idValue 区域id
     * @return 区域名称
     */
    private static String getLocalAreaName(Long idValue) {
        try {
            // TODO Bean 提取为成员变量
            ITbAreaService areaService = SpringUtils.getBean(ITbAreaService.class);
            TbArea tbArea = areaService.selectTbAreaByAreaId(idValue);
            return localAreaNameFun().apply(tbArea);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 设置本地化国家名称
     *
     * @param t          操作对象
     * @param idGetter   获取国家id的方法
     * @param nameSetter 设置国家名称的方法
     * @param <T>        操作对象类型
     */
    public static <T> void setLocalCountryName(T t, Function<T, Long> idGetter, BiConsumer<T, String> nameSetter) {
        // 获取 areaId 值
        Long idValue = idGetter.apply(t);

        // 处理id值（假设处理逻辑是将id值转换为name）
        String localName = getLocalCountryName(idValue);

        // 设置 areaName 值
        nameSetter.accept(t, localName);
    }

    /**
     * 获取本地化国家名称
     *
     * @param idValue 国家id
     * @return 国家名称
     */
    private static String getLocalCountryName(Long idValue) {
        try {
            ITbCountryService areaService = SpringUtils.getBean(ITbCountryService.class);
            TbCountry country = areaService.selectTbCountryByCountryId(idValue);
            return localCountryNameFun().apply(country);
        } catch (Exception e) {
            return "";
        }
    }


    /**
     * 设置本地化区域和国家名称
     *
     * @param t                 操作对象
     * @param areaIdGetter      获取区域id的方法
     * @param countryIdGetter   获取国家id的方法
     * @param areaNameSetter    设置区域名称的方法
     * @param countryNameSetter 设置国家名称的方法
     * @param <T>               操作对象类型
     */
    public static <T> void setLocalAreaAndCountryName(T t, Function<T, Long> areaIdGetter, Function<T, Long> countryIdGetter, BiConsumer<T, String> areaNameSetter, BiConsumer<T, String> countryNameSetter) {
        // 获取 areaId 值
        Long areaIdValue = areaIdGetter.apply(t);
        Long countryIdValue = countryIdGetter.apply(t);

        // 处理id值（假设处理逻辑是将id值转换为name）
        String localAreaName = getLocalAreaName(areaIdValue);

        // 设置 areaName 值
        areaNameSetter.accept(t, localAreaName);

        String localCountryName = getLocalCountryName(countryIdValue);

        // 设置 areaName 值
        countryNameSetter.accept(t, localCountryName);
    }

    /**
     * 批量设置本地化区域名称
     *
     * @param list       操作对象列表
     * @param idGetter   获取区域id的方法
     * @param nameSetter 设置区域名称的方法
     * @param <T>        操作对象类型
     */
    public static <T> void setLocalAreaNameBatch(List<T> list, Function<T, Long> idGetter, BiConsumer<T, String> nameSetter) {
        list.forEach(t -> setLocalAreaName(t, idGetter, nameSetter));
    }

    /**
     * 批量设置本地化国家名称
     *
     * @param list       操作对象列表
     * @param idGetter   获取国家id的方法
     * @param nameSetter 设置国家名称的方法
     * @param <T>        操作对象类型
     */
    public static <T> void setLocalCountryNameBatch(List<T> list, Function<T, Long> idGetter, BiConsumer<T, String> nameSetter) {
        list.forEach(t -> setLocalCountryName(t, idGetter, nameSetter));
    }

    /**
     * 批量设置本地化区域和国家名称
     *
     * @param list              操作对象列表
     * @param areaIdGetter      获取区域id的方法
     * @param countryIdGetter   获取国家id的方法
     * @param areaNameSetter    设置区域名称的方法
     * @param countryNameSetter 设置国家名称的方法
     * @param <T>               操作对象类型
     */
    public static <T> void setLocalAreaAndCountryNameBatch(List<T> list, Function<T, Long> areaIdGetter, Function<T, Long> countryIdGetter, BiConsumer<T, String> areaNameSetter, BiConsumer<T, String> countryNameSetter) {
        list.forEach(t -> setLocalAreaAndCountryName(t, areaIdGetter, countryIdGetter, areaNameSetter, countryNameSetter));
    }

    // =================================================================================================================

    /**
     * 获取不同列表数据 存在的区域（下拉）数据，去重排序，返回区域id和对应国际化名称
     * 
     * 如需按照不同语言环境排序： countries.sort((o1, o2) -> Collator.getInstance(Locale.CHINESE).compare(o1.getCountryName(), o2.getCountryName()));
     */
    public static List<Pair<Long, String>> selectAreasByCurUser(List<Long> areaIds) {
        if (CollectionUtils.isEmpty(areaIds)) {
            return Collections.emptyList();
        }
        Map<Long, TbArea> allAreaMap = SpringUtils.getBean(ITbAreaService.class).allAreaMap();

        return areaIds.stream().map(allAreaMap::get)
                .filter(Objects::nonNull)
                .sorted(Comparator.comparing(TbArea::getAreaNameUS))
                .map(area -> Pair.of(area.getAreaId(), LocalUtils.localAreaNameFun().apply(area)))
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 获取不同列表数据 存在的国家（下拉）数据，去重排序，返回国家id和对应国际化名称
     * 
     * @param countryIds 国家id列表
     */
    public static List<Pair<Long, String>> selectCountriesByCurUser(List<Long> countryIds) {
        if (CollectionUtils.isEmpty(countryIds)) {
            return Collections.emptyList();
        }
        Map<Long, TbCountry> allCountryMap = SpringUtils.getBean(ITbCountryService.class).allCountryMap();

        return countryIds.stream().map(allCountryMap::get)
                .filter(Objects::nonNull)
                .sorted(Comparator.comparing(TbCountry::getCountryNameUS))
                .peek(System.out::println)
                .peek(country -> System.out.println(LocalUtils.localCountryNameFun().apply(country)))
                .map(country -> Pair.of(country.getCountryId(), LocalUtils.localCountryNameFun().apply(country)))
                .peek(System.out::println)
                .distinct()
                .collect(Collectors.toList());
    }

}