package com.tanpu.community.service;

import com.tanpu.common.api.CommonResp;
import com.tanpu.community.api.beans.resp.CoursePackageSimpleResp;
import com.tanpu.community.api.beans.vo.feign.activity.OfflineActivitySimpleResp;
import com.tanpu.community.api.beans.vo.feign.course.CourseSimpleResp;
import com.tanpu.community.api.beans.vo.feign.course.ShortVideoBaseInfoResp;
import com.tanpu.community.api.beans.vo.feign.fatools.UserInfoResp;
import com.tanpu.community.api.beans.vo.feign.product.FundCompanyVO;
import com.tanpu.community.api.beans.vo.feign.product.ProductInfoVO;
import com.tanpu.community.api.beans.vo.feign.zhibo.ZhiboListResp;
import com.tanpu.community.cache.LocalCache;
import com.tanpu.community.feign.activity.FeignClientForActivity;
import com.tanpu.community.feign.course.FeignClientForCourse;
import com.tanpu.community.feign.fatools.FeignClientForFatools;
import com.tanpu.community.feign.product.FeignClientForProducts;
import com.tanpu.community.feign.product.FeignForFund;
import com.tanpu.community.feign.product.FeignForPublicFund;
import com.tanpu.community.feign.tanpuroom.FeignClientForTanpuroom;
import com.tanpu.community.feign.zhibo.FeignClientForZhibo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

@Slf4j
@Service
public class FeignService {

    @Resource
    private FeignClientForTanpuroom feignClientForTanpuroom;

    @Resource
    private FeignClientForZhibo feignClientForZhibo;

    @Resource
    private FeignClientForProducts feignForProduct;

    @Resource
    private FeignClientForCourse feignForCourse;


    @Resource
    private FeignForFund feignForFund;

    @Resource
    private FeignForPublicFund feignForPublicFund;

    @Resource
    private FeignClientForFatools feignClientForFatools;


    @Resource
    private FeignClientForActivity feignClientForActivity;

    @Resource
    private LocalCache localCache;


    public UserInfoResp getUserInfoById(String userId) {

        List<UserInfoResp> userList = getUserList(Collections.singletonList(userId));
        if (CollectionUtils.isEmpty(userList)) {
            return null;
        }
        return userList.get(0);
    }

    public List<ShortVideoBaseInfoResp> batchGetShortVideoBaseInfo(List<String> sourceIds) {
        return batchExecute("batchGetShortVideoBaseInfo_", sourceIds, ShortVideoBaseInfoResp.class,
                ShortVideoBaseInfoResp::getSourceId, ids -> {
                    CommonResp<List<ShortVideoBaseInfoResp>> resp = feignClientForTanpuroom.getShortVideoBaseInfo(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<CourseSimpleResp> getCourseSimpleList(List<String> courseIds) {
        return batchExecute("getCourseSimpleList_", courseIds, CourseSimpleResp.class,
                CourseSimpleResp::getCourseId, ids -> {
                    CommonResp<List<CourseSimpleResp>> resp = feignForCourse.getCourseSimpleList(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<CoursePackageSimpleResp> getCoursePackageList(List<String> coursePackageIds) {
        return batchExecute("getCoursePackageList", coursePackageIds, CoursePackageSimpleResp.class,
                CoursePackageSimpleResp::getCoursePackageId, ids -> {
                    CommonResp<List<CoursePackageSimpleResp>> resp = feignForCourse.getCoursePackageListByUserId(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<ZhiboListResp> getZhiboSimpleList(List<String> zhiboIds) {
        return batchExecute("getZhiboSimpleList_", zhiboIds, ZhiboListResp.class,
                ZhiboListResp::getId, ids -> {
                    CommonResp<List<ZhiboListResp>> resp = feignClientForZhibo.simpleList(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<OfflineActivitySimpleResp> getActivitySimpleList(List<String> activityIds) {
        return batchExecute("getActivitySimpleList_", activityIds, OfflineActivitySimpleResp.class,
                OfflineActivitySimpleResp::getActivityId, ids -> {
                    CommonResp<List<OfflineActivitySimpleResp>> resp = feignClientForActivity.simpleListByIds(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<UserInfoResp> getUserList(List<String> userIds) {
        return batchExecute("getUserList_", userIds, UserInfoResp.class,
                UserInfoResp::getUserId, ids -> {
                    return feignClientForFatools.queryUserListNew(ids);
                });
    }

    public List<ProductInfoVO> getProductInfoByIdsForTopic(List<String> fundIds) {
        return batchExecute("getProductInfoByIdsForTopic_", fundIds, ProductInfoVO.class,
                ProductInfoVO::getFundId, ids -> {
                    CommonResp<List<ProductInfoVO>> resp = feignForProduct.getProductInfoByIds(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<ProductInfoVO> getProductInfoByIdsForTheme(List<String> fundIds) {
        return batchExecute("getProductInfoByIdsForTheme_", fundIds, ProductInfoVO.class,
                ProductInfoVO::getFundId, ids -> {
                    CommonResp<List<ProductInfoVO>> resp = feignForProduct.getProductInfoByIds(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<ProductInfoVO> getFundList(List<String> fundIds) {
        return batchExecute("getFundList", fundIds, ProductInfoVO.class,
                ProductInfoVO::getFundId, ids -> {
                    CommonResp<List<ProductInfoVO>> resp = feignForFund.getProductList(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<ProductInfoVO> getPrivateFundList(List<String> fundIds) {
        return batchExecute("getPrivateFundList", fundIds, ProductInfoVO.class,
                ProductInfoVO::getFundId, ids -> {
                    CommonResp<List<ProductInfoVO>> resp = feignForFund.getPrivateFundList(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<ProductInfoVO> getPublicFundList(List<String> fundIds) {
        return batchExecute("getPublicFundList", fundIds, ProductInfoVO.class,
                ProductInfoVO::getFundId, ids -> {
                    CommonResp<List<ProductInfoVO>> resp = feignForPublicFund.getProductList(ids);
                    if (resp.isSuccess()) {
                        return resp.getData();
                    } else {
                        return new ArrayList<>();
                    }
                });
    }

    public List<FundCompanyVO> getFundCompany(List<String> companyIds) {
        return batchExecute("getCoursePackageList", companyIds, FundCompanyVO.class,
                FundCompanyVO::getCompanyId, ids -> {
                    CommonResp<FundCompanyVO> resp = feignForProduct.getFundCompanyInfo(ids.get(0));
                    if (resp.isSuccess()) {
                        return Arrays.asList(resp.getData());
                    } else {
                        return new ArrayList<>();
                    }
                });
    }


    private <T> List<T> batchExecute(String keyPrefix,
                                     List<String> keys,
                                     Class<T> clz,
                                     Function<T, String> getKeyFunc,
                                     Function<List<String>, List<T>> feignFunc) {
        List<T> retList = new ArrayList<>();
        List<String> feignIds = new ArrayList<>();
        for (String key : keys) {
            String cacheKey = keyPrefix + key;

            T ret = localCache.getObject(cacheKey, clz);
            if (ret != null) {
                retList.add(ret);
            } else {
                feignIds.add(key);
            }
        }

        if (!feignIds.isEmpty()) {
            List<T> remoteList = feignFunc.apply(feignIds);
//            log.info("batchExecute feign returns {} -> {}", JSON.toJSONString(feignIds), JSON.toJSONString(remoteList));

            if (remoteList != null) {
                retList.addAll(remoteList);
                retList.forEach(r -> {
                    localCache.putObject(keyPrefix + getKeyFunc.apply(r), r);
                });
            }
        }
//        log.info("batchExecute {} : {} -> {}", keyPrefix, JSON.toJSONString(keys), JSON.toJSONString(retList));
        return retList;
    }
}