/* (C) 2021 YiRing, Inc. */
package com.yiring.app.web.example;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.dev33.satoken.annotation.SaIgnore;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.yiring.app.domain.user.UserExtension;
import com.yiring.app.domain.user.UserExtensionRepository;
import com.yiring.app.vo.user.UserExtensionVo;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.util.Auths;
import com.yiring.common.annotation.DownloadResponse;
import com.yiring.common.annotation.RateLimiter;
import com.yiring.common.core.I18n;
import com.yiring.common.core.Result;
import com.yiring.common.core.Retriever;
import com.yiring.common.core.Status;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.service.FileManageService;
import com.yiring.common.util.Commons;
import com.yiring.common.util.FileUtils;
import com.yiring.common.utils.RepositoryUtil;
import com.yiring.common.validation.group.Group;
import com.yiring.common.vo.PageVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Example;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * 示例接口
 *
 * @author Jim
 */

@Slf4j
@Validated
@ApiSupport(order = 0)
@Tag(name = "【Examples】 示例", description = "Example")
@RequestMapping("/example/")
@RestController
@RequiredArgsConstructor
public class ExampleController {

    final I18n i18n;
    final Auths auths;
    final UserExtensionRepository userExtensionRepository;
    final FileManageService fileManageService;
    final Retriever retriever;

    @RateLimiter(count = 1)
    @Operation(summary = "Hello World")
    @GetMapping
    public Result<String> hello() {
        return Result.ok("example.hello");
    }

    /**
     * 测试失败自定义状态信息输出
     */
    @Operation(summary = "测试失败")
    @GetMapping("fail")
    public void fail() {
        // 1. 直接抛出异常
        // Status.BAD_REQUEST.expose("Code.1");
        // 2. 手动抛出异常
        // throw Status.BAD_REQUEST.exception("Code.1");
        // throw BusinessException.i18n("Code.1");
        // throw new FailStatusException(Status.BAD_REQUEST, "Code.1");
        // 3. 重试抛出异常
        throw retriever.execute(
            ctx -> {
                throw new RuntimeException("retry test fail");
            },
            ctx -> Status.BAD_REQUEST.exception("Code.1"),
            Retriever::defaultPolicy
        );
    }

    @SaCheckLogin
    @Operation(summary = "分页条件查询")
    @GetMapping("page")
    public Result<PageVo<String>> page(@ParameterObject @Validated PageParam param) {
        log.debug("PageParam: {}", param);
        log.debug("Pageable: {}", PageParam.toPageable(param));

        // 常用的分页、条件查询工具类函数
        // 1. Specifications.of()
        // 2. Specifications.exist()
        // 3. PageParam.toPageable()
        // 4. PageVo.build()/PageVo.toPageVo()
        // 5. RepositoryUtil.find()

        String text = i18n.get("example.hello");
        List<String> data = Arrays.asList(text.split(" "));
        PageVo<String> vo = PageVo.build(data);
        return Result.ok(vo);
    }

    @Operation(summary = "JSON 传参")
    @PostMapping("json")
    public Result<PageVo<String>> json(
        @RequestBody(required = false) @Validated(Group.Optional.class) PageParam param
    ) {
        return page(param);
    }

    @SaIgnore
    @DownloadResponse
    @SneakyThrows(IOException.class)
    @Operation(summary = "文件下载")
    @GetMapping(value = "download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void download(HttpServletResponse response) {
        ClassPathResource resource = new ClassPathResource("static/cat.jpg");
        FileUtils.download(response, resource.getFile());
    }

    @Operation(summary = "文件上传")
    @PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Result<String> upload(
        @Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file,
        @ParameterObject @Validated IdParam param
    ) {
        log.info("upload params: {}", param);

        try {
            String link = fileManageService.upload(file);
            return Result.ok(link);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw Status.BAD_REQUEST.exception();
        }
    }

    @SaCheckSafe
    @SaCheckLogin
    @Operation(summary = "查询用户属性")
    @GetMapping("findUserExtensionInfo")
    public Result<UserExtensionVo> findUserExtensionInfo() {
        User user = auths.getLoginUser();
        Example<UserExtension> example = Example.of(new UserExtension(user));
        UserExtension ext = RepositoryUtil.find(userExtensionRepository, example);
        UserExtensionVo vo = Commons.transform(ext, UserExtensionVo.class);
        return Result.ok(vo);
    }
}
