package com.neusoft.smart.pos.ota.service;


import com.neusoft.smart.pos.dto.ota.request.ApkStrategyQueryRequest;
import com.neusoft.smart.pos.dto.ota.request.ApkVersionRequest;
import com.neusoft.smart.pos.dto.ota.request.AppInfoRequest;
import com.neusoft.smart.pos.dto.ota.request.AppQueryRequest;
import com.neusoft.smart.pos.dto.ota.request.AppStrategyGroupRequest;
import com.neusoft.smart.pos.dto.ota.response.ApkStrategyGroupResponse;
import com.neusoft.smart.pos.dto.ota.response.ApkStrategyResponse;
import com.neusoft.smart.pos.dto.ota.response.ApkVersionResponse;
import com.neusoft.smart.pos.dto.ota.response.AppInfoResponse;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.task.TaskExecutor;
import com.neusoft.smart.pos.framework.utils.BeanUtil;
import com.neusoft.smart.pos.ota.constants.OTAErrorCode;
import com.neusoft.smart.pos.ota.persistent.domain.ApkStrategy;
import com.neusoft.smart.pos.ota.persistent.domain.ApkStrategyGroup;
import com.neusoft.smart.pos.ota.persistent.domain.ApkVersion;
import com.neusoft.smart.pos.ota.persistent.domain.AppInfo;
import com.neusoft.smart.pos.ota.persistent.ext.domain.ApkStrategyQuery;
import com.neusoft.smart.pos.ota.persistent.ext.domain.AppQuery;
import com.neusoft.smart.pos.ota.persistent.repository.AppRepository;
import com.neusoft.smart.pos.ota.task.AppStrategyTask;
import com.neusoft.smart.pos.redis.bean.AppVersion;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AppService {
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    @Autowired
    private AppRepository appRepository;
    
    @Autowired
    private TaskExecutor taskExecutor;
    
    /**
     * @param appQueryRequest
     * @return
     */
    public List<AppInfoResponse> getList(AppQueryRequest appQueryRequest) {
        List<AppInfo> poList = appRepository.getAppList(BeanUtil.parse(appQueryRequest, AppQuery.class));
        return BeanUtil.parseList(poList, AppInfoResponse.class);
    }
    
    public Integer getCount(AppQueryRequest appQueryRequest) {
        return appRepository.getAppCount(BeanUtil.parse(appQueryRequest, AppQuery.class));
    }
    
    @Transactional
    public void createOrUpdateApp(AppInfoRequest appInfo) {
        AppQuery appQuery = new AppQuery();
        appQuery.setAppName2(appInfo.getAppName());
        appQuery.setAppPackage2(appInfo.getAppPackage());
        if (null != appInfo.getId()) {
            appQuery.setId(appInfo.getId());
        }
        if (appRepository.getAppCount(appQuery) > 0) {
            throw new BusinessCommonException(OTAErrorCode.APP_DUPLICATE);
        }
        AppInfo po = BeanUtil.parse(appInfo, AppInfo.class);
        po.setStatus(null);
        if (null != appInfo.getId()) {
            appRepository.updateApp(po);
        } else {
            po.setCreateBy(RequestHeaderUtil.getUserId());
            po.setOrganizationId(RequestHeaderUtil.getOrgId());
            appRepository.createApp(po);
        }
    }
    
    @Transactional
    public void createApk(ApkVersionRequest apkVersion) {
        if (appRepository.queryApkCount(apkVersion.getAppId(), apkVersion.getApkVersion()) > 0) {
            throw new BusinessCommonException(OTAErrorCode.APK_VERSION_DUPLICATE);
        }
        ApkVersion po = BeanUtil.parse(apkVersion, ApkVersion.class);
        po.setCreateBy(RequestHeaderUtil.getUserId());
        appRepository.createApk(po);
        AppInfo appInfo = appRepository.getAppById(apkVersion.getAppId());
        BoundHashOperations<String, String, AppVersion> operations = redisTemplate.boundHashOps("apkVersion");
        AppVersion appVersion = new AppVersion();
        appVersion.setAppId(appInfo.getId());
        appVersion.setAppName(appInfo.getAppName());
        appVersion.setPackageName(appInfo.getAppPackage());
        appVersion.setName(apkVersion.getApkName());
        appVersion.setInfo(apkVersion.getApkReleaseNote());
        appVersion.setSize(apkVersion.getApkSize());
        appVersion.setVersion(apkVersion.getApkVersion());
        appVersion.setPath(apkVersion.getApkDownloadPath());
        operations.put(appInfo.getAppPackage() + "." + appInfo.getAppName(), appVersion);
    }
    
    /**
     * 通过appId 获取所有有效apk文件
     *
     * @param appId
     * @return
     */
    public List<ApkVersionResponse> getApkVersionList(Integer appId) {
        List<ApkVersion> poList = appRepository.getApkVersionList(appId);
        return BeanUtil.parseList(poList, ApkVersionResponse.class);
    }
    
    @Transactional
    public void changeStatus(Integer appId, Integer status) {
        AppInfo appInfo = new AppInfo();
        appInfo.setId(appId);
        appInfo.setStatus(status);
        appRepository.updateApp(appInfo);
        
        BoundHashOperations<String, String, AppVersion> operations = redisTemplate.boundHashOps("apkVersion");
        AppVersion appVersion = operations.values().stream().filter(apkVersion -> apkVersion.getAppId().equals(appId)).findAny().orElse(null);
        if (null != appVersion) {
            operations.delete(appVersion.getPackageName() + "." + appVersion.getAppName());
        }
    }
    
    
    public List<ApkStrategyGroupResponse> getApkStrategyGroupList(ApkStrategyQueryRequest apkStrategyQueryRequest) {
        List<ApkStrategyGroup> poList = appRepository.getApkStrategyGroupList(BeanUtil.parse(apkStrategyQueryRequest, ApkStrategyQuery.class));
        return BeanUtil.parseList(poList, ApkStrategyGroupResponse.class);
    }
    
    public Integer getApkStrategyGroupCount(ApkStrategyQueryRequest apkStrategyQueryRequest) {
        return appRepository.getApkStrategyGroupCount(BeanUtil.parse(apkStrategyQueryRequest, ApkStrategyQuery.class));
    }
    
    @Transactional
    public void saveGroup(AppStrategyGroupRequest appStrategyGroupRequest) {
        if (appRepository.getStrategyCountByName(appStrategyGroupRequest.getStrategyName()) > 0) {
            throw new BusinessCommonException(OTAErrorCode.STRATEGY_NAME_DUPLICATE);
        }
        ApkStrategyGroup apkStrategyGroup = new ApkStrategyGroup();
        apkStrategyGroup.setName(appStrategyGroupRequest.getStrategyName());
        apkStrategyGroup.setUpgradeTime(appStrategyGroupRequest.getUpgradeTime());
        apkStrategyGroup.setIsForce(appStrategyGroupRequest.getIsForce());
        apkStrategyGroup.setCreateBy(RequestHeaderUtil.getUserId());
        apkStrategyGroup.setOrganizationId(RequestHeaderUtil.getOrgId());
        appRepository.createStrategyGroup(apkStrategyGroup);
        Integer groupId = apkStrategyGroup.getId();
        
        appStrategyGroupRequest.getDeviceIds().forEach(deviceId ->
                appStrategyGroupRequest.getApps().forEach(app -> {
                    ApkStrategy apkStrategy = new ApkStrategy();
                    apkStrategy.setDeviceId(deviceId);
                    apkStrategy.setGroupId(groupId);
                    apkStrategy.setAppId(app.getAppId());
                    apkStrategy.setApkId(app.getApkId());
                    appRepository.createStrategy(apkStrategy);
                })
        );
        AppStrategyTask appStrategyTask = new AppStrategyTask();
        appStrategyTask.setAppStrategyGroupRequest(appStrategyGroupRequest);
        taskExecutor.getExecutorService().submit(appStrategyTask);
    }
    
    public List<AppInfoResponse> getApps(Integer groupId) {
        List<ApkStrategy> apkStrategyList = appRepository.getApkStrategies(groupId);
        List<Integer> appIds = apkStrategyList.stream().map(ApkStrategy::getAppId).collect(Collectors.toList());
        AppQuery appQuery = new AppQuery();
        appQuery.setIsPage(false);
        appQuery.setIds(appIds);
        List<AppInfo> appInfos = appRepository.getAppList(appQuery);
        
        List<Integer> apkIds = apkStrategyList.stream().map(ApkStrategy::getApkId).collect(Collectors.toList());
        List<ApkVersion> apkVersions = appRepository.getApkVersionListByIds(apkIds);
        List<AppInfoResponse> appWithApkBos = new ArrayList<>();
        
        appInfos.forEach(app -> {
            ApkVersion apkVersion = apkVersions.parallelStream().filter(apk -> apk.getAppId().equals(app.getId())).findAny().get();
            AppInfoResponse appWithApkBo = new AppInfoResponse();
            BeanUtils.copyProperties(app, appWithApkBo);
            BeanUtils.copyProperties(apkVersion, appWithApkBo);
            appWithApkBos.add(appWithApkBo);
        });
        
        return appWithApkBos;
    }
    
    public List<ApkStrategyResponse> getApkStrategyList(Integer groupId) {
        List<ApkStrategy> poList = appRepository.getApkStrategies(groupId);
        return BeanUtil.parseList(poList, ApkStrategyResponse.class);
    }
    
}
