package cokr.xit.ens.modules.kkomydoc.presentation;

import cokr.xit.ens.core.aop.EnsResponseVO;
import cokr.xit.ens.core.utils.crypto.AES256;
import cokr.xit.ens.core.utils.crypto.Crypto;
import cokr.xit.ens.modules.common.code.UseNativeQuery;
import com.google.common.collect.Lists;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.transaction.Transactional;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import static cokr.xit.ens.modules.kkomydoc.domain.QSendDetailKkoMydoc.sendDetailKkoMydoc;

@Tag(name = "KkoMydocCryptoController")
@Slf4j
@RequiredArgsConstructor
@RestController
public class KkoMydocCryptoController {

    private final JPAQueryFactory query;
    private final JdbcTemplate jdbcTemplate;
    private int BATCH_SIZE = 1000;

    @Operation(summary = "주민번호 암호화(전체)")
    @PostMapping(value = "/kko/mydoc/crypto/enc/jid/all", produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional
    public ResponseEntity<EnsResponseVO> encJidAll() {

        AES256 aes256 = new AES256(Crypto.AES256.getKey());
        Long totCnt = Lists.partition(query.selectFrom(sendDetailKkoMydoc)
                        .where(sendDetailKkoMydoc.mkJid.length().eq(13)
                                .or(sendDetailKkoMydoc.mkJid.length().eq(14)))
                        .fetch(), this.BATCH_SIZE)
                .stream()
                .map(sendDetailKkoMydocs -> {
                    jdbcTemplate.batchUpdate("update " + UseNativeQuery.SendDetailKkoMydoc.getTblNm() + " set mk_jid = ? where send_detail_id = ?", new BatchPreparedStatementSetter() {
                        @Override
                        public void setValues(PreparedStatement ps, int i) throws SQLException {
                            ps.setString(1, aes256.encrypt(sendDetailKkoMydocs.get(i).getMkJid()));
                            ps.setLong(2, sendDetailKkoMydocs.get(i).getSendDetailId());
                        }

                        @Override
                        public int getBatchSize() {
                            return sendDetailKkoMydocs.size();
                        }
                    });

                    return Long.valueOf(sendDetailKkoMydocs.size());
                })
                .reduce(Long::sum)
                .orElse(0L);

        EnsResponseVO responseVO = EnsResponseVO.okBuilder()
                .resultInfo(totCnt + " updated success")
                .build();
        return new ResponseEntity<EnsResponseVO>(responseVO, HttpStatus.OK);
    }

    @Operation(summary = "주민번호 복호화(전체)")
    @PostMapping(value = "/kko/mydoc/crypto/dec/jid/all", produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional
    public ResponseEntity<EnsResponseVO> decJidAll() {

        AES256 aes256 = new AES256(Crypto.AES256.getKey());
        Long totCnt = Lists.partition(query.selectFrom(sendDetailKkoMydoc)
                        .where(sendDetailKkoMydoc.mkJid.length().eq(24))
                        .fetch(), this.BATCH_SIZE)
                .stream()
                .map(sendDetailKkoMydocs -> {
                    jdbcTemplate.batchUpdate("update " + UseNativeQuery.SendDetailKkoMydoc.getTblNm() + " set mk_jid = ? where send_detail_id = ?", new BatchPreparedStatementSetter() {
                        @Override
                        public void setValues(PreparedStatement ps, int i) throws SQLException {
                            ps.setString(1, aes256.decrypt(sendDetailKkoMydocs.get(i).getMkJid()));
                            ps.setLong(2, sendDetailKkoMydocs.get(i).getSendDetailId());
                        }

                        @Override
                        public int getBatchSize() {
                            return sendDetailKkoMydocs.size();
                        }
                    });

                    return Long.valueOf(sendDetailKkoMydocs.size());
                })
                .reduce(Long::sum)
                .orElse(0L);

        EnsResponseVO responseVO = EnsResponseVO.okBuilder()
                .resultInfo(totCnt + " updated success")
                .build();
        return new ResponseEntity<EnsResponseVO>(responseVO, HttpStatus.OK);
    }
}
