package com.sonic.shark.controller.web;

import com.sonic.common.auth.domains.Session;
import com.sonic.common.rpc.Result;
import com.sonic.common.utils.IpAddressUtils;
import com.sonic.sdk.api.annotation.IgnoreAuth;
import com.sonic.shark.domain.bo.NsfwRecognitionResult;
import com.sonic.shark.domain.bo.S3StsToken;
import com.sonic.shark.domain.input.GetNsfwResultInput;
import com.sonic.shark.domain.input.StsTokenInput;
import com.sonic.shark.enums.BizResultCode;
import com.sonic.shark.enums.S3BizTypeMappingEnum;
import com.sonic.shark.enums.S3BucketNameEnum;
import com.sonic.shark.enums.ToastResultCode;
import com.sonic.shark.limit.RequestLimit;
import com.sonic.shark.service.*;
import com.sonic.shark.utils.AwsS3Utils;
import com.sonic.shark.utils.Constants;
import com.sonic.shark.utils.LimitUtils;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;

import javax.servlet.http.HttpServletRequest;


/**
 * AWS S3 文件处理
 */
@RestController
@Slf4j
public class S3Web {

    @Autowired
    private S3StsService s3StsService;

    @Autowired
    private FileUploadLogService fileUploadLogService;

    @Autowired
    private AwsS3Utils awsS3Utils;
    @Autowired
    private NsfwConfigService nsfwConfigService;
    @Autowired
    private ImageCheckService imageCheckService;
    @Autowired
    private NsfwLogService nsfwLogService;
    @Autowired
    private LimitUtils limitUtils;

    /**
     * 24小时内请求的数量达到了100次，直接限流
     */
    @IgnoreAuth
    @RequestLimit(count = 500, time = 86400000)
    @ApiOperation(value = "获取s3的sts的授权token", tags = {"WEB-S3文件"})
    @PostMapping(value = "/web/file/sts-tk")
    public Result fileStsToken(@RequestBody StsTokenInput input, @ApiParam(hidden = true) Session session, @ApiParam(hidden = true) HttpServletRequest request) {
        //对用户做限流、鉴权的一系列操作
        boolean bl = limitUtils.limitCheckByBizAndUserId(session.getUserId(), "stsToken", 200);
        ToastResultCode.SYS_OPERATOR_24_HOUR_ERROR.check(bl);
        //校验枚举类型，只能是固定的枚举类型才能无需登录拉取token
        ToastResultCode.STS_BIZ_TYPE_ERROR.check(session.getUserId() == null && input.getBizTypeEnum().getLoginCheck());
        //如果用户ID为空则存放到0的空间目录下
        session.setUserId(session.getUserId() == null ? 0L : session.getUserId());
        S3BucketNameEnum s3BucketNameEnum = input.getBizTypeEnum().getS3BucketNameEnum();
        S3StsToken s3StsToken = s3StsService.getStsToken(input.getBizTypeEnum(), session.getUserId(), input.getSuffix());
        s3StsToken.setBucket(s3BucketNameEnum.getBucketName());
        s3StsToken.setEndPoint(s3BucketNameEnum.getEndPoint());
        s3StsToken.setUrlPath(s3BucketNameEnum.getRootUrl() + s3StsToken.getPath());
        s3StsToken.setRegion(s3BucketNameEnum.getRegion().id());
        //保存数据到日志表中
        fileUploadLogService.save(session.getUserId(), s3StsToken, IpAddressUtils.getIpAddress(request), session.getEndpoint());
        return Result.success(s3StsToken);
    }


    @RequestLimit(count = 500, time = 86400000)
    @ApiOperation(value = "获取鉴黄结果", tags = {"WEB-S3文件"})
    @PostMapping(value = "/web/file/check")
    public Result fileNsfwCheck(@RequestBody GetNsfwResultInput input, @ApiParam(hidden = true) Session session, @ApiParam(hidden = true) HttpServletRequest request) {
        //对用户做限流、鉴权的一系列操作
        boolean bl = limitUtils.limitCheckByBizAndUserId(session.getUserId(), "nsfw", 200);
        ToastResultCode.SYS_OPERATOR_24_HOUR_ERROR.check(bl);
        S3BucketNameEnum s3BucketNameEnum = input.getBizTypeEnum().getS3BucketNameEnum();
        //6.14.0 操作权限判断
        optAccessCheck(session.getUserId(), input.getBizTypeEnum(), input.getFileFullPath());
        HeadObjectResponse objectHeader = awsS3Utils.getObjectHeader(s3BucketNameEnum, input.getFileFullPath());
        ToastResultCode.FILE_NOT_EXISTS_ERROR.check(objectHeader == null);
        ToastResultCode.FILE_MAX_SIZE_ERROR.check(objectHeader.contentLength() != null && objectHeader.contentLength() > Constants.FILE_MAX_BYTE);
        ToastResultCode.FILE_TYPE_ERROR.check(!Constants.FILE_TYPE_LIST.contains(objectHeader.contentType()));

        //图片鉴黄操作
        NsfwRecognitionResult nsfwRecognitionResult = nsfwConfigService.nsfwRecognition(s3BucketNameEnum, input.getFileFullPath());
        //鉴黄不通过将图片删除掉
        if (nsfwRecognitionResult.getBl() != null && nsfwRecognitionResult.getBl()) {
            //先不删除图片，将被鉴黄的图片数据给存储起来（后面用定时任务去删除）
            nsfwLogService.add(session.getUserId(), s3BucketNameEnum, input.getFileFullPath(), nsfwRecognitionResult);
            BizResultCode.BIZ_NSFW_VALIDATE_ERROR.check(true);
        }
        //将鉴黄结果存储在缓存中
        imageCheckService.addImageCheckResult(s3BucketNameEnum.getRootUrl() + input.getFileFullPath());
        return Result.success(nsfwRecognitionResult.getBl());
    }


    /**
     * 操作权限校验
     * @param currentUserId
     * @param s3BizTypeMappingEnum
     * @param filePath
     */
    private void optAccessCheck(Long currentUserId, S3BizTypeMappingEnum s3BizTypeMappingEnum, String filePath) {
        //获取到根路径
        String homePath = s3BizTypeMappingEnum.getFilePath();
        //获取需要移除掉的根路径的长度
        int removeIndex = filePath.indexOf(homePath) + homePath.length();
        log.info("===> optAccessCheck removeIndex : {}", removeIndex);
        //移除掉根路径
        String removePath = filePath.substring(removeIndex);
        log.info("===> optAccessCheck removePath : {}", removePath);
        //从移除掉根路径的文件路径中获取第一个分隔符
        int userIdIndex = removePath.indexOf("/");
        String userId = removePath.substring(0, userIdIndex);
        log.info("===> optAccessCheck userId : {}", userId);
        //校验当前操作用户和url连接中的用户是否匹配，如果不匹配则直接抛出异常
        ToastResultCode.NO_OPERATION_AUTH.check(!currentUserId.toString().equals(userId));
    }

}
