package com.sunyard.chsm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunyard.chsm.dto.AppQuery;
import com.sunyard.chsm.dto.AppSave;
import com.sunyard.chsm.dto.AppView;
import com.sunyard.chsm.enums.EnableStatus;
import com.sunyard.chsm.mapper.AppServiceMapper;
import com.sunyard.chsm.mapper.ApplicationMapper;
import com.sunyard.chsm.mapper.CryptoServiceMapper;
import com.sunyard.chsm.model.entity.AppService;
import com.sunyard.chsm.model.entity.Application;
import com.sunyard.chsm.model.entity.CryptoService;
import com.sunyard.chsm.service.ApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author liulu
 * @since 2024/10/30
 */
@Slf4j
@Service
@Transactional
public class ApplicationServiceImpl implements ApplicationService {

    @Resource
    private ApplicationMapper applicationMapper;
    @Resource
    private AppServiceMapper appServiceMapper;
    @Resource
    private CryptoServiceMapper cryptoServiceMapper;

    @Override
    public Page<AppView> selectPageList(AppQuery query) {
        IPage<Application> page = applicationMapper.selectPage(
                new Page<>(query.getPageNumber(), query.getPageSize()),
                new LambdaQueryWrapper<Application>()
                        .like(StringUtils.hasText(query.getName()), Application::getName, query.getName())
                        .eq(StringUtils.hasText(query.getStatus()), Application::getStatus, query.getStatus())
                        .orderByDesc(Application::getCreateTime)
        );
        List<Application> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        }
        List<Long> appIds = records.stream().map(Application::getId).collect(Collectors.toList());
        List<AppService> appServices = appServiceMapper.selectByAppIds(appIds);
        Map<Long, List<Long>> appServiceMap = appServices.stream()
                .collect(Collectors.groupingBy(AppService::getApplicationId,
                        Collectors.mapping(AppService::getServiceId, Collectors.toList())));
        List<CryptoService> services = cryptoServiceMapper.selectBatchIds(appServices.stream().map(AppService::getServiceId).collect(Collectors.toList()));
        Map<Long, String> snMap = services.stream().collect(Collectors.toMap(CryptoService::getId, CryptoService::getName));

        List<AppView> viewList = records.stream()
                .map(it -> {
                    AppView view = new AppView();
                    BeanUtils.copyProperties(it, view);
                    List<Long> sIds = appServiceMap.getOrDefault(it.getId(), Collections.emptyList());
                    view.setServiceIds(sIds.stream().map(String::valueOf).collect(Collectors.toList()));
                    String sn = sIds.stream()
                            .map(snMap::get)
                            .filter(Objects::nonNull)
                            .collect(Collectors.joining(","));
                    view.setServiceNames(sn);
                    view.setStatusText(EnableStatus.of(it.getStatus()).getDesc());
                    return view;
                })
                .collect(Collectors.toList());

        return new Page<AppView>(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(viewList);
    }

    @Override
    public Long save(AppSave save) {
        checkName(save.getName());
        LocalDateTime now = LocalDateTime.now();
        Application app = new Application();
        app.setId(IdWorker.getId());
        app.setAppKey(IdWorker.get32UUID());
        app.setAppSecret(IdWorker.get32UUID());
        app.setName(save.getName());
        app.setStatus(EnableStatus.ENABLED.getCode());
        app.setRemark(save.getRemark());
        app.setCreateTime(now);

        applicationMapper.insert(app);

        for (Long serviceId : save.getServiceIds()) {

            AppService as = new AppService();
            as.setId(IdWorker.getId());
            as.setApplicationId(app.getId());
            as.setServiceId(serviceId);
            as.setCreateTime(now);
            appServiceMapper.insert(as);
        }
        return app.getId();
    }

    @Override
    public void update(AppSave update) {
        Assert.notNull(update.getId(), "id不能为空");
        Application exist = applicationMapper.selectById(update.getId());
        Assert.notNull(exist, "要更新的数据不存在");

        if (!Objects.equals(exist.getName(), update.getName())) {
            checkName(update.getName());
        }
        LocalDateTime now = LocalDateTime.now();
        Application upApp = new Application();
        upApp.setId(update.getId());
        upApp.setName(update.getName());
        upApp.setRemark(update.getRemark());
        upApp.setUpdateTime(now);
        applicationMapper.updateById(upApp);

        appServiceMapper.deleteByAppId(update.getId());
        for (Long serviceId : update.getServiceIds()) {

            AppService as = new AppService();
            as.setId(IdWorker.getId());
            as.setApplicationId(exist.getId());
            as.setServiceId(serviceId);
            as.setCreateTime(now);
            appServiceMapper.insert(as);
        }

    }

    private void checkName(String name) {
        Assert.hasText(name, "名称不能为空");
        Application exist = applicationMapper.selectOne(
                new LambdaQueryWrapper<Application>()
                        .eq(Application::getName, name)

        );
        Assert.isNull(exist, "应用名称已存在");
    }

    @Override
    public void enable(Long id) {
        Application app = applicationMapper.selectById(id);
        Assert.notNull(app, "业务应用不存在");
        Assert.isTrue(Objects.equals(EnableStatus.DISABLED.getCode(), app.getStatus()),
                "当前应用不是停用状态,不支持启用");

        Application upApp = new Application();
        upApp.setId(id);
        upApp.setStatus(EnableStatus.ENABLED.getCode());
        upApp.setUpdateTime(LocalDateTime.now());
        applicationMapper.updateById(upApp);
    }

    @Override
    public void disable(Long id) {
        Application app = applicationMapper.selectById(id);
        Assert.notNull(app, "业务应用不存在");
        Assert.isTrue(Objects.equals(EnableStatus.ENABLED.getCode(), app.getStatus()),
                "当前应用不是启用状态,不支持停用");

        Application upApp = new Application();
        upApp.setId(id);
        upApp.setStatus(EnableStatus.DISABLED.getCode());
        upApp.setUpdateTime(LocalDateTime.now());
        applicationMapper.updateById(upApp);
    }

    @Override
    public void resetCredential(Long id) {
        Application app = applicationMapper.selectById(id);
        Assert.notNull(app, "业务应用不存在");

        Application upApp = new Application();
        upApp.setId(id);
        upApp.setAppKey(IdWorker.get32UUID());
        upApp.setAppSecret(IdWorker.get32UUID());
        upApp.setUpdateTime(LocalDateTime.now());
        applicationMapper.updateById(upApp);
    }

    @Override
    public void delete(Long id) {
        applicationMapper.deleteById(id);
        appServiceMapper.deleteByAppId(id);
    }
}
