package cn.reghao.bnt.web.devops.app.controller;

import cn.reghao.bnt.web.devops.app.model.vo.AppConfigDetail;
import cn.reghao.bnt.web.util.SelectOption;
import cn.reghao.bnt.web.devops.app.model.dto.AppConfigDto;
import cn.reghao.bnt.web.devops.app.model.dto.AppConfigUpdateDto;
import cn.reghao.bnt.web.devops.app.model.dto.CopyAppDto;
import cn.reghao.bnt.web.devops.app.service.AppBuildService;
import cn.reghao.bnt.web.devops.app.db.query.AppBuildQuery;
import cn.reghao.bnt.web.devops.app.model.po.config.AppConfig;
import cn.reghao.bnt.web.devops.app.model.vo.AppConfigVO;
import cn.reghao.bnt.web.devops.build.db.repository.CompilerConfigRepository;
import cn.reghao.bnt.web.devops.build.db.repository.PackerConfigRepository;
import cn.reghao.bnt.web.devops.build.db.repository.RepoAuthConfigRepository;
import cn.reghao.jutil.jdk.web.db.PageList;
import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.jutil.web.WebResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2019-08-30 18:49:15
 */
@Slf4j
@Tag(name = "应用配置页面")
@RestController
@RequestMapping("/api/devops/app/config/app")
public class AppConfigController {
    private int pageSize = 10;
    private final AppBuildQuery appBuildQuery;
    private final RepoAuthConfigRepository repoAuthConfigRepository;
    private final CompilerConfigRepository compilerConfigRepository;
    private final PackerConfigRepository packerConfigRepository;
    private final AppBuildService appBuildService;

    public AppConfigController(AppBuildQuery appBuildQuery, RepoAuthConfigRepository repoAuthConfigRepository,
                               CompilerConfigRepository compilerConfigRepository,
                               PackerConfigRepository packerConfigRepository, AppBuildService appBuildService) {
        this.appBuildQuery = appBuildQuery;
        this.repoAuthConfigRepository = repoAuthConfigRepository;
        this.compilerConfigRepository = compilerConfigRepository;
        this.packerConfigRepository = packerConfigRepository;
        this.appBuildService = appBuildService;
    }

    @Operation(summary = "应用配置列表页面", description = "N")
    @GetMapping(value = "")
    public String appConfigPage(@RequestParam(value = "env") String env,
                                @RequestParam(value = "appType") String appType,
                                @RequestParam(value = "pn") int pageNumber) {
        PageRequest pageRequest = PageRequest.of(pageNumber-1, pageSize);
        Page<AppConfigVO> appPage = appBuildQuery.getByEnvAndType(env, appType, pageRequest);
        PageList<AppConfigVO> pageList = getPageList(appPage);
        return WebResult.success(pageList);
    }

    private PageList<AppConfigVO> getPageList(Page<AppConfigVO> page) {
        int pageNumber = page.getNumber() + 1;
        int pageSize = page.getSize();
        long total = page.getTotalElements();
        List<AppConfigVO> list = page.getContent();
        return PageList.pageList(pageNumber, pageSize, (int) total, list);
    }

    @Operation(summary = "构建配置列表", description = "N")
    @GetMapping("/build_config")
    public String addAppConfigPage() {
        Map<String, Object> map = getBuildConfig();
        return WebResult.success(map);
    }

    private Map<String, Object> getBuildConfig() {
        List<SelectOption> repoAuths = repoAuthConfigRepository.findAll().stream()
                .map(repoAuthConfig -> new SelectOption(repoAuthConfig.getName(), String.valueOf(repoAuthConfig.getId())))
                .collect(Collectors.toList());
        List<SelectOption> compilers = compilerConfigRepository.findAllByDeletedFalse().stream()
                .map(compilerConfig -> new SelectOption(compilerConfig.getName(), String.valueOf(compilerConfig.getId())))
                .collect(Collectors.toList());
        List<SelectOption> packers = packerConfigRepository.findAllByDeletedFalse().stream()
                .map(packerConfig -> new SelectOption(packerConfig.getName(), String.valueOf(packerConfig.getId())))
                .collect(Collectors.toList());

        Map<String, Object> map = new HashMap<>();
        map.put("repoAuthList", repoAuths);
        map.put("compilerList", compilers);
        map.put("packerList", packers);
        return map;
    }

    @Operation(summary = "应用配置详情页面", description = "N")
    @GetMapping("/detail")
    public String appConfigPage(@RequestParam("appId") String appId) {
        AppConfig app = appBuildQuery.getAppConfig(appId);
        return WebResult.success(new AppConfigDetail(app));
    }

    @Operation(summary = "应用绑定的域名", description = "N")
    @GetMapping("/bind_domain")
    public String getAppBindDomains(@RequestParam("appId") String appId) {
        AppConfig app = appBuildQuery.getAppConfig(appId);
        return WebResult.success(app.getDomains());
    }

    @Operation(summary = "添加应用配置", description = "N")
    @PostMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
    public String addAppConfig(@Validated AppConfigDto appConfigDto) {
        Result result = appBuildService.createAppBuild(appConfigDto);
        return WebResult.result(result);
    }

    @Operation(summary = "复制应用配置", description = "N")
    @PostMapping(value = "/copy", produces = MediaType.APPLICATION_JSON_VALUE)
    public String copyAppConfig(@Validated CopyAppDto copyAppDto) {
        Result result = appBuildService.createByCopy(copyAppDto);
        return WebResult.result(result);
    }

    @Operation(summary = "修改应用配置", description = "N")
    @PostMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE)
    public String updateAppConfig(@Validated AppConfigUpdateDto appConfigUpdateDto) {
        Result result = appBuildService.updateAppConfig(appConfigUpdateDto);
        return WebResult.result(result);
    }

    // TODO 使用 @PathVariable 注解时 Hibernate 会根据传入的 id 自动查找相应的实体
    @Operation(summary = "删除应用配置", description = "N")
    @PostMapping(value = "/delete", produces = MediaType.APPLICATION_JSON_VALUE)
    public String deleteAppConfig(String appId) {
        Result result = appBuildService.deleteAppBuild(appId);
        return WebResult.result(result);
    }

    @Operation(summary = "清空应用本地仓库", description = "N")
    @PostMapping(value = "/clear_repo", produces = MediaType.APPLICATION_JSON_VALUE)
    public String deleteAppLocalRepo(String appId) {
        Result result = appBuildService.clearLocalRepo(appId);
        return WebResult.result(result);
    }
}
