package com.eactive.eai.rms.data.entity.onl.authserver;

import com.eactive.eai.data.entity.onl.authserver.QTokenIssuanceLog;
import com.eactive.eai.data.entity.onl.authserver.TokenIssuanceLog;
import com.eactive.eai.data.jpa.AbstractDataService;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@Service
@Transactional
public class TokenIssuanceLogService  extends AbstractDataService<TokenIssuanceLog, String, TokenIssuanceLogRepository>{
    private final TokenIssuanceLogRepository repository;
    private final JPAQueryFactory queryFactory;

    public TokenIssuanceLogService(TokenIssuanceLogRepository repository, EntityManager entityManager) {
        this.repository = repository;
        this.queryFactory = new JPAQueryFactory(entityManager);
    }

    public List<TokenIssuanceLog> findRecentLogsForRestriction(String clientId, LocalDateTime startDateTime) {
        Predicate predicate = createRestrictionPredicate(clientId, startDateTime);
        return StreamSupport.stream(repository.findAll(predicate).spliterator(), false)
                .collect(Collectors.toList());
    }

    public long countRecentLogsForRestriction(String clientId, LocalDateTime startDateTime) {
        QTokenIssuanceLog qTokenIssuanceLog = QTokenIssuanceLog.tokenIssuanceLog;
        return queryFactory.select(qTokenIssuanceLog.count())
                .from(qTokenIssuanceLog)
                .where(createRestrictionPredicate(clientId, startDateTime))
                .fetchOne();
    }

    private Predicate createRestrictionPredicate(String clientId, LocalDateTime startDateTime) {
        QTokenIssuanceLog qTokenIssuanceLog = QTokenIssuanceLog.tokenIssuanceLog;

        return qTokenIssuanceLog.clientId.eq(clientId)
                .and(qTokenIssuanceLog.issuanceDateTime.goe(startDateTime))
                .and(qTokenIssuanceLog.restrictionExemptYn.eq("N").or(qTokenIssuanceLog.restrictionExemptYn.isNull()));
    }


    public long countRecentFailedLogs(String clientId, LocalDateTime startDateTime) {
        QTokenIssuanceLog qTokenIssuanceLog = QTokenIssuanceLog.tokenIssuanceLog;
        return queryFactory.select(qTokenIssuanceLog.count())
                .from(qTokenIssuanceLog)
                .where(createFailedLogsPredicate(clientId, startDateTime))
                .fetchOne();
    }

    private Predicate createFailedLogsPredicate(String clientId, LocalDateTime startDateTime) {
        QTokenIssuanceLog qTokenIssuanceLog = QTokenIssuanceLog.tokenIssuanceLog;

        return qTokenIssuanceLog.clientId.eq(clientId)
                .and(qTokenIssuanceLog.issuanceDateTime.goe(startDateTime))
                .and(qTokenIssuanceLog.successYn.eq("N"))
                .and(qTokenIssuanceLog.restrictionExemptYn.eq("N").or(qTokenIssuanceLog.restrictionExemptYn.isNull()));
    }

    public void exemptRestrictionForClient(String clientId, LocalDateTime startDateTime) {
        QTokenIssuanceLog qTokenIssuanceLog = QTokenIssuanceLog.tokenIssuanceLog;
        queryFactory.update(qTokenIssuanceLog)
                .set(qTokenIssuanceLog.restrictionExemptYn, "Y")
                .where(qTokenIssuanceLog.clientId.eq(clientId)
                        .and(qTokenIssuanceLog.issuanceDateTime.goe(startDateTime)))
                .execute();

    }

    public long deleteOldLogs(int daysToKeep) {
        QTokenIssuanceLog qTokenIssuanceLog = QTokenIssuanceLog.tokenIssuanceLog;
        LocalDateTime cutoffDate = LocalDateTime.now().minusDays(daysToKeep);

        return queryFactory.delete(qTokenIssuanceLog)
                .where(qTokenIssuanceLog.issuanceDateTime.before(cutoffDate))
                .execute();
    }
}
