package com.iqser.red.service.persistence.management.v1.processor.service.persistence;

import static com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository.categoryMatches;
import static com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository.dateBetween;
import static com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository.objectIdMatches;
import static com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository.userMatches;

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

import jakarta.transaction.Transactional;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.audit.AuditEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditSearchRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.CategoryModel;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

@Service
@RequiredArgsConstructor
public class AuditPersistenceService {

    private final AuditRepository auditRepository;


    public void audit(AuditRequest auditRequest) {

        insertRecord(auditRequest);
    }


    @SneakyThrows
    public void insertRecord(AuditRequest auditRequest) {

        var auditModel = new AuditEntity();
        BeanUtils.copyProperties(auditRequest, auditModel);
        auditModel.setRecordDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));

        auditRepository.save(auditModel);

    }


    public List<CategoryModel> getCategories() {

        return auditRepository.findCategories();

    }


    public Page<AuditEntity> search(AuditSearchRequest auditRequest) {

        if (auditRequest.getPageSize() == 0) {
            auditRequest.setPageSize(50);
        }

        if (auditRequest.getFrom() == null) {
            auditRequest.setFrom(OffsetDateTime.now().minusYears(30).truncatedTo(ChronoUnit.MILLIS));
        }
        if (auditRequest.getTo() == null) {
            auditRequest.setTo(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
        }

        var spec = Specification.where(dateBetween(auditRequest.getFrom(), auditRequest.getTo()));
        if (auditRequest.getCategory() != null) {
            spec = spec.and(categoryMatches(auditRequest.getCategory()));
        }
        if (auditRequest.getUserId() != null) {
            spec = spec.and(userMatches(auditRequest.getUserId()));
        }
        if (auditRequest.getObjectId() != null) {
            spec = spec.and(objectIdMatches(auditRequest.getObjectId()));
        }

        return auditRepository.findAll(spec, PageRequest.of(auditRequest.getPage(), auditRequest.getPageSize(), Sort.Direction.DESC, "recordDate"));
    }

}
