package com.xjrsoft.module.form.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.toolkit.MPJWrappers;
import com.xjrsoft.common.annotation.XjrLog;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.model.generator.FormConfig;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.form.dto.AddFormCodeFirstDto;
import com.xjrsoft.module.form.dto.AddFormDataFirstDto;
import com.xjrsoft.module.form.dto.DateTestDto;
import com.xjrsoft.module.form.dto.FormTemplateDeskPageDto;
import com.xjrsoft.module.form.dto.FormTemplateListDto;
import com.xjrsoft.module.form.dto.FormTemplatePageDto;
import com.xjrsoft.module.form.dto.UpdateFormCodeFirstDto;
import com.xjrsoft.module.form.dto.UpdateFormDataFirstDto;
import com.xjrsoft.module.form.dto.UpdateTemplateStatusDto;
import com.xjrsoft.module.form.entity.FormHistory;
import com.xjrsoft.module.form.entity.FormRelease;
import com.xjrsoft.module.form.entity.FormTemplate;
import com.xjrsoft.module.form.service.IFormHistoryService;
import com.xjrsoft.module.form.service.IFormReleaseService;
import com.xjrsoft.module.form.service.IFormTemplateService;
import com.xjrsoft.module.form.vo.FormTemplateListVo;
import com.xjrsoft.module.form.vo.FormTemplatePageVo;
import com.xjrsoft.module.form.vo.FormTemplateVo;
import com.xjrsoft.module.generator.dto.DataFirstPreviewDto;
import com.xjrsoft.module.generator.entity.ListConfig;
import com.xjrsoft.module.generator.entity.MenuConfig;
import com.xjrsoft.module.generator.entity.TableConfig;
import com.xjrsoft.module.generator.service.IGeneratorService;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 表单设计模板  前端控制器
 * </p>
 *
 * @author tzx
 * @since 2022-05-09
 */
@RestController
@RequestMapping(GlobalConstant.FORM_MODULE_PREFIX + "/template")
@Api(value = GlobalConstant.FORM_MODULE_PREFIX + "/template", tags = "自定义表单-代码生成器 模板设计")
@AllArgsConstructor
public class FormTemplateController {

    private final IFormTemplateService formTemplateService;

    private final IFormHistoryService formHistoryService;

    private final IFormReleaseService formReleaseService;

    private final IGeneratorService generatorService;



    @GetMapping(value = "/list")
    @ApiOperation(value = "表单设计模板(不分页)")
    @XjrLog(value = "表单设计模板")
    public R list(@Valid FormTemplateListDto dto) {
        List<FormTemplate> list = formTemplateService.list(Wrappers.lambdaQuery(FormTemplate.class)
                .eq(FormTemplate::getFormType, dto.getType())
                .eq(dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                .orderByDesc(FormTemplate::getCreateDate)
                .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplateListVo.class).contains(x.getProperty())));

        List<FormTemplateListVo> formTemplateListVos = BeanUtil.copyToList(list, FormTemplateListVo.class);
        return R.ok(formTemplateListVos);
    }

    @GetMapping(value = "/page")
    @ApiOperation(value = "表单设计模板(分页),过滤未启用数据")
    @XjrLog(value = "表单设计模板")
    public R page(@Valid FormTemplatePageDto dto) {

        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .eq(FormTemplate::getEnabledMark,YesOrNoEnum.YES.getCode())
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/enabled-page")
    @ApiOperation(value = "表单设计模板(分页)，不过滤未启用数据")
    @XjrLog(value = "表单设计模板")
    public R pageEnabled(@Valid FormTemplatePageDto dto) {

        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "表单设计模板详情")
    @XjrLog(value = "表单设计模板详情")
    public R info(@RequestParam Long id) {
        FormTemplate template = formTemplateService.getById(id);
        if (template == null) {
            return R.error("找不到此数据！");
        }
        return R.ok(BeanUtil.toBean(template, FormTemplateVo.class));
    }

    @GetMapping(value = "/info/multi")
    @ApiOperation(value = "表单设计模板详情(批量查询)")
    @XjrLog(value = "表单设计模板详情(批量查询)")
    public R multiInfo(@RequestParam String id) {
        List<FormTemplate> formTemplates = formTemplateService.listByIds(Arrays.asList(id.split(StringPool.COMMA)));
        List<FormTemplateVo> formTemplateVos = BeanUtil.copyToList(formTemplates, FormTemplateVo.class);
        return R.ok(formTemplateVos);
    }

    @PutMapping("/status")
    @ApiOperation(value = "修改表单状态")
    @XjrLog(value = "修改表单状态")
    public R updateEnabled(@Valid @RequestBody UpdateTemplateStatusDto dto) {
        //根据id修改表单enabledMark
        return R.ok(formTemplateService.update(Wrappers.<FormTemplate>update().lambda().set(FormTemplate::getEnabledMark, dto.getEnabledMark()).eq(FormTemplate::getId, dto.getId())));
    }

    @PostMapping(value = "/data-first")
    @ApiOperation(value = "数据优先 新增")
    @XjrLog(value = "数据优先新增")
    public R addDataFirst(@Valid @RequestBody AddFormDataFirstDto dto) {
        return R.ok(formTemplateService.addDataFirst(dto));
    }

    @PostMapping(value = "/code-first")
    @ApiOperation(value = "界面优先 或者  简易模板 新增")
    @XjrLog(value = "界面优先 或者 简易模板新增")
    public R addCodeFirst(@Valid @RequestBody AddFormCodeFirstDto dto) {
        return R.ok(formTemplateService.addCodeFirst(dto));
    }

    @PutMapping(value = "/data-first")
    @ApiOperation(value = "修改数据优先")
    @XjrLog(value = "修改数据优先")
    public R updateDataFirst(@Valid @RequestBody UpdateFormDataFirstDto dto) {
        return R.ok(formTemplateService.updateDataFirst(dto));
    }


    @PutMapping(value = "/code-first")
    @ApiOperation(value = "修改界面优先")
    @XjrLog(value = "修改界面优先")
    public R updateCodeFirst(@Valid @RequestBody UpdateFormCodeFirstDto dto){
        return R.ok(formTemplateService.updateCodeFirst(dto));
    }

    @DeleteMapping
    @ApiOperation(value = "删除")
    public R delete(@Valid @RequestBody List<Long> ids) {
        formHistoryService.remove(Wrappers.lambdaQuery(FormHistory.class).in(FormHistory::getFormId, ids));
        return R.ok(formTemplateService.removeBatchByIds(ids));
    }

    @PostMapping(value = "/test-code")
    @ApiOperation(value = "表单测试代码生成器")
    @XjrLog(value = "测试表单预览代码生成器")
    public R test(@Valid @RequestBody DateTestDto dto){
        FormRelease formRelease = formReleaseService.getById(dto.getFormReleaseId());
        FormTemplate formTemplate = formTemplateService.getById(dto.getFormTemplateId());
        JSONObject configJson = JSON.parseObject(formRelease.getConfigJson());
        JSONObject formJson = JSON.parseObject(formTemplate.getFormJson());
        dto.setDatabaseId(formJson.get("databaseId").toString());
        dto.setTableConfigs(JSONObject.parseArray(formJson.getString("tableConfigs"),TableConfig.class));
        dto.setFormJson(JSON.parseObject(formJson.getString("formJson"),FormConfig.class));
        dto.setListConfig(JSON.parseObject(configJson.getString("listConfig"), ListConfig.class));
        dto.setMenuConfig(JSON.parseObject(configJson.getString("menuConfig"), MenuConfig.class));
        dto.setOutputConfig(dto.getOutputConfig());
        return R.ok(generatorService.getPreviewCodes(BeanUtil.toBean(dto, DataFirstPreviewDto.class)));
    }

    @GetMapping(value = "/desk-form-page")
    @ApiOperation(value = "桌面设计-复杂列表页使用(分页),过滤未启用数据")
    @XjrLog(value = "表单设计模板")
    public R deskFormPage(@Valid FormTemplateDeskPageDto dto) {
        //只需要已发布的，和系统表单的数据
        List<Long> releaseIds = formReleaseService.list().stream().map(FormRelease::getFormId).collect(Collectors.toList());
        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .eq(FormTemplate::getEnabledMark,YesOrNoEnum.YES.getCode())
                        .in(dto.getType() == YesOrNoEnum.YES.getCode() && CollectionUtil.isNotEmpty(releaseIds),FormTemplate::getId,releaseIds) //自定义表单需要过滤出来已发布的数据
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

}

