package com.samsung.user.controller;

import com.samsung.accesslog.AccessLogService;
import com.samsung.accesslog.entity.SysUseLog;
import com.samsung.accesslog.enums.ReqType;
import com.samsung.authentication.Account;
import com.samsung.batch.enums.LogFlag;
import com.samsung.common.IdGenService;
import com.samsung.common.entity.JwtResponse;
import com.samsung.common.util.JwtUtil;
import com.samsung.common.util.WebUtil;
import com.samsung.core.exception.AuthorizationException;
import com.samsung.user.UserService;
import com.samsung.user.entity.User;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

@RestController
@Log4j2
public class ImpersonationController {

    @Value("${access-log.store-type}")
    private String storeType;

    @Value("${node-id}")
    private String node;

    private final UserService userService;

    private final IdGenService idGenService;

    private final AccessLogService accessLogService;

    private final WebUtil webUtil;

    private final JwtUtil jwtUtil;

    public ImpersonationController(UserService userService, IdGenService idGenService, AccessLogService accessLogService, WebUtil webUtil, JwtUtil jwtUtil) {
        this.userService = userService;
        this.idGenService = idGenService;
        this.accessLogService = accessLogService;
        this.webUtil = webUtil;
        this.jwtUtil = jwtUtil;
    }

    @GetMapping("/impersonation/login")
    @Operation(summary = "대리 로그인")
    public JwtResponse loginById(HttpServletRequest request,
                                 @RequestParam(value = "userId") String userId) {
        User admin = Account.currentUser();
        // 시스템 어드민인지 체크
        assert admin != null;
        if(admin.isSystemAdminUser()){
            User user = userService.getUserById(userId);
            assert user != null;

            impersonationLog(request, admin, user, "Start.",  LogFlag.IMPERSONATION_START.getValue());
//            response.addHeader("original-user-id", admin.getUserId());
            return new JwtResponse(jwtUtil.generateToken(user), userId);
        }
        throw new AuthorizationException( admin.getUserId() + " is not system administrator." );
    }

    @PutMapping("/impersonation/logout")
    @Operation(summary = "대리 로그인 종료")
    public ResponseEntity<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        String originalUserId = request.getHeader("original-user-id");
        assert originalUserId != null;
        User  admin = userService.getUserById(originalUserId);
        User user = Account.currentUser();
        assert user != null;
        impersonationLog(request, admin, user, "End.", LogFlag.IMPERSONATION_END.getValue());
        response.addHeader("original-user-id", null);
        return ResponseEntity.ok().build();
    }

    private void impersonationLog(HttpServletRequest request, User admin, User user, String s, String logFlag) {
        SysUseLog sysUseLog = new SysUseLog();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd HHmmssSSS", Locale.getDefault());
        String sTime = formatter.format(new Date());
        sysUseLog.setLogOccurId(idGenService.getNextStringId());
        sysUseLog.setNodeId(node);
        sysUseLog.setUserId(admin.getUserId());
        sysUseLog.setUseFromDate(sTime.substring(0, 8));
        sysUseLog.setUseFromHhmmss(sTime.substring(9, 15));
        sysUseLog.setUseThruDatetime(new Date());
        sysUseLog.setUseIp(webUtil.getClientIp(request));
        sysUseLog.setReqType(ReqType.WEB);
        sysUseLog.setFirstRegDatetime(new Date());
        sysUseLog.setLogFlag(logFlag);
        sysUseLog.setDescription("Original User : " + admin.getUserId() + "Impersonate User : " + user.getUserId() + s);


        try {
            if ("db".equalsIgnoreCase(storeType)) {
                accessLogService.insertAccessLog(sysUseLog);
            } else {
                accessLogService.logAccess(sysUseLog);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}
