package com.eactive.eai.rms.common.acl.audit.service;

import java.time.LocalDateTime;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.rms.common.acl.audit.domain.AuditLog;
import com.eactive.eai.rms.common.acl.audit.domain.AuditPoint;
import com.eactive.eai.rms.common.acl.audit.port.in.IsAuditableUsecase;
import com.eactive.eai.rms.common.acl.audit.port.in.SaveAuditLogUseCase;
import com.eactive.eai.rms.common.acl.audit.port.in.SelectDetailAuditLogUseCase;
import com.eactive.eai.rms.common.acl.audit.port.in.SelectListAuditLogCommand;
import com.eactive.eai.rms.common.acl.audit.port.in.SelectListAuditLogUseCase;
import com.eactive.eai.rms.common.acl.audit.port.out.SaveAuditLogPort;
import com.eactive.eai.rms.common.acl.audit.port.out.SelectDetailAuditLogPort;
import com.eactive.eai.rms.common.acl.audit.port.out.SelectListAuditLogPort;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@Transactional(transactionManager = "transactionManagerForEMS")
class AuditLogService
		implements SaveAuditLogUseCase, SelectListAuditLogUseCase, SelectDetailAuditLogUseCase, IsAuditableUsecase {

	private final SelectListAuditLogPort selectListAuditLogPort;

	private final SelectDetailAuditLogPort selectDetailAuditLogPort;

	private final SaveAuditLogPort saveAuditLogPort;

	private final Map<String, AuditPoint> auditPoints;

	@Autowired
	public AuditLogService(SelectListAuditLogPort selectListAuditLogPort,
			SelectDetailAuditLogPort selectDetailAuditLogPort, SaveAuditLogPort saveAuditLogPort,
			@Qualifier("auditPoints") Map<String, AuditPoint> auditPoints) {
		this.selectListAuditLogPort = selectListAuditLogPort;
		this.selectDetailAuditLogPort = selectDetailAuditLogPort;
		this.saveAuditLogPort = saveAuditLogPort;
		this.auditPoints = auditPoints;
	}

	@Override
	public Page<AuditLog> selectList(Pageable pageable, SelectListAuditLogCommand command) {
		return selectListAuditLogPort.findPage(pageable, command);
	}

	public AuditLog selectDetail(Long id) {
		return selectDetailAuditLogPort.getById(id);
	}

	@Override
	public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
			String parameters, String message) {

		AuditLog auditLog = new AuditLog(systemCode, logType, command, userId, remoteAddress);
		String auditPointKey = AuditPoint.generateKey(logType, systemCode, command);
		AuditPoint auditPoint = auditPoints.get(auditPointKey);

		auditLog.setLogTypeText(auditPoint.getLogTypeText());
		auditLog.setLastModifiedDate(LocalDateTime.now());
		auditLog.setParameters(parameters);
		auditLog.setMessage(message);

		saveAuditLogPort.save(auditLog);
	}

	@Override
	public boolean isAuditable(String userId, String command, String logType, String systemCode) {
		if (StringUtils.isAnyBlank(userId, command, logType, systemCode)) {
			log
					.debug("audit log save : logType={}, cmd={}, user={}, systemCode={}", logType, command, userId,
							systemCode);
			return false;
		}

		String loggingPointKey = AuditPoint.generateKey(logType, systemCode, command);
		return auditPoints.containsKey(loggingPointKey);
	}

}
