package com.interplug.qcast.biz.login;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.interplug.qcast.biz.login.dto.JoinUser;
import com.interplug.qcast.biz.login.dto.LoginUser;
import com.interplug.qcast.biz.login.dto.UserLoginResponse;
import com.interplug.qcast.biz.login.dto.UserPassword;
import com.interplug.qcast.biz.login.dto.UserResponse;
import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException;
import com.interplug.qcast.config.message.Messages;
import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping("/api/login")
@RequiredArgsConstructor
public class LoginController {
  // @Autowired private LoginService loginService;
  private final LoginService loginService;

  @Autowired
  Messages message;

  @Value("${qsp.aes256.key}")
  String loginPasswordAesKey;

  @Value("${qsp.auto.login.aes256.key}")
  String autoLoginAesKey;


  /**
   * Q.CAST III에 로그인하여 사용자 정보를 획득한다.
   * 
   * @param loginUser LoginUser
   * @return UserLoginResponse
   * @throws Exception
   */
  @Operation(description = "Q.CAST III에 로그인하여 사용자 정보를 획득한다.")
  @PostMapping("/v1.0/login")
  @ResponseStatus(HttpStatus.CREATED)
  public UserLoginResponse login(@RequestBody LoginUser loginUser) throws Exception {
    return loginService.getLogin(loginUser);
  }

  @PostMapping("/v1.0/user")
  @ResponseStatus(HttpStatus.CREATED)
  public UserResponse getUser(@RequestBody LoginUser loginUser) {
    return loginService.getUser(loginUser);
  }

  /**
   * 가입 신청 정보를 등록한다.
   * 
   * @param joinUser JoinUser
   * @return DefaultResponse
   * @throws Exception
   */
  @Operation(description = "가입 신청 정보를 등록한다.")
  @PostMapping("/v1.0/user/join")
  @ResponseStatus(HttpStatus.CREATED)
  public DefaultResponse joinUser(@RequestBody JoinUser joinUser) throws Exception {
    return loginService.joinUser(joinUser);
  }

  /**
   * 비밀번호를 초기화한다.
   * 
   * @param userPassword UserPassword
   * @return DefaultResponse
   * @throws Exception
   */
  @Operation(description = "비밀번호를 초기화한다.")
  @PatchMapping("/v1.0/user/init-password")
  public DefaultResponse initPassword(@RequestBody UserPassword userPassword) throws Exception {
    return loginService.initPassword(userPassword);
  }

  /**
   * 비밀번호를 변경한다.
   * 
   * @param userPassword UserPassword
   * @return DefaultResponse
   * @throws Exception
   */
  @Operation(description = "비밀번호를 변경한다.")
  @PatchMapping("/v1.0/user/change-password")
  public DefaultResponse changePassword(@RequestBody UserPassword userPassword) throws Exception {
    return loginService.changePassword(userPassword);
  }

  /**
   * 자동 로그인에 사용하는 아이디를 암호화한다.
   * 
   * @param loginUser LoginUser
   * @return String
   * @throws Exception
   */
  @Operation(description = "자동 로그인에 사용하는 아이디를 암호화한다.")
  @PostMapping("/v1.0/user/login/autoLoginEncryptData")
  public String getAutoLoginEncryptData(@RequestBody LoginUser loginUser) throws Exception {

    String loginEncryptId = "";

    if ("".equals(loginUser.getLoginId()) || loginUser.getLoginId() == null) {
      throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
          message.getMessage("common.message.required.data", "User Id"));
    }

    try {
      // [0]. AES 암호화 키 : 날짜(YYYYMMDD) + autoLoginAesKey
      LocalDate today = LocalDate.now();
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
      String formattedDate = today.format(formatter);
      String encryptKey = formattedDate + autoLoginAesKey;

      // [1]. 암호화 진행
      byte[] keyData = loginPasswordAesKey.getBytes();
      SecretKey secureKey = new SecretKeySpec(keyData, "AES");
      Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
      c.init(Cipher.ENCRYPT_MODE, secureKey,
          new IvParameterSpec(encryptKey.substring(0, 16).getBytes()));
      byte[] encrypted = c.doFinal(loginUser.getLoginId().getBytes("UTF-8"));

      // [2]. 암호화 값 셋팅
      loginEncryptId = new String(Base64.getEncoder().encode(encrypted));;

    } catch (Exception e) {
      throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR,
          message.getMessage("common.message.error"));
    }

    return loginEncryptId;
  }

  /**
   * 자동 로그인에 사용하는 아이디를 복호화한다.
   * 
   * @param loginUser LoginUser
   * @return String
   * @throws Exception
   */
  @Operation(description = "자동 로그인에 사용하는 아이디를 복호화한다.")
  @PostMapping("/v1.0/user/login/autoLoginDecryptData")
  public String getAutoLoginDecryptData(@RequestBody LoginUser loginUser) throws Exception {

    String loginDecryptId = "";

    if ("".equals(loginUser.getLoginId()) || loginUser.getLoginId() == null) {
      throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
          message.getMessage("common.message.required.data", "User Id"));
    }

    try {
      // [0]. AES 암호화 키 : 날짜(YYYYMMDD) + autoLoginAesKey
      LocalDate today = LocalDate.now();
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
      String formattedDate = today.format(formatter);
      String decryptKey = formattedDate + autoLoginAesKey;

      // [1]. 복호화 진행
      byte[] keyData = loginPasswordAesKey.getBytes();
      SecretKey secureKey = new SecretKeySpec(keyData, "AES");
      Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
      c.init(Cipher.DECRYPT_MODE, secureKey,
          new IvParameterSpec(decryptKey.substring(0, 16).getBytes("UTF-8")));

      byte[] byteStr = Base64.getDecoder().decode(loginUser.getLoginId().getBytes());

      // [2]. 복호화 값 셋팅
      loginDecryptId = new String(c.doFinal(byteStr), "UTF-8");

    } catch (Exception e) {
      throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR,
          message.getMessage("common.message.error"));
    }

    return loginDecryptId;
  }

}
