package org.jpos.tcpay.db.repository;

import org.jpos.tcpay.db.entity.PosTransactionReversal;
import org.jpos.util.AppLogger;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * JPA implementation of PosTransactionReversalRepository
 * Uses EntityManager for all database operations
 */
public class PosTransactionReversalRepositoryImpl implements PosTransactionReversalRepository {
    
    private final EntityManagerFactory emf;
    private final AppLogger logger = new AppLogger();
    
    public PosTransactionReversalRepositoryImpl(EntityManagerFactory emf) {
        this.emf = emf;
    }
    
    @Override
    public PosTransactionReversal save(PosTransactionReversal reversal) {
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        
        try {
            tx.begin();
            
            if (reversal.getId() == null) {
                em.persist(reversal);
            } else {
                reversal = em.merge(reversal);
            }
            
            tx.commit();
            logger.log("Saved reversal: " + reversal.getId());
            return reversal;
            
        } catch (Exception e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            logger.log("Error saving reversal: " + e.getMessage());
            throw new RuntimeException("Failed to save reversal", e);
        } finally {
            em.close();
        }
    }
    
    @Override
    public Optional<PosTransactionReversal> findById(Long id) {
        EntityManager em = emf.createEntityManager();
        try {
            PosTransactionReversal reversal = em.find(PosTransactionReversal.class, id);
            return Optional.ofNullable(reversal);
        } catch (Exception e) {
            logger.log("Error finding reversal by ID: " + e.getMessage());
            return Optional.empty();
        } finally {
            em.close();
        }
    }
    
    @Override
    public List<PosTransactionReversal> findByOriginalTempTxnId(Long originalTempTxnId) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<PosTransactionReversal> query = em.createQuery(
                "SELECT r FROM PosTransactionReversal r WHERE r.originalTempTxnId = :originalTempTxnId", 
                PosTransactionReversal.class
            );
            query.setParameter("originalTempTxnId", originalTempTxnId);
            
            return query.getResultList();
            
        } catch (Exception e) {
            logger.log("Error finding reversals by original temp txn ID: " + e.getMessage());
            return List.of();
        } finally {
            em.close();
        }
    }
    
    @Override
    public boolean existsByOriginalTempTxnId(Long originalTempTxnId) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<Long> query = em.createQuery(
                "SELECT COUNT(r) FROM PosTransactionReversal r WHERE r.originalTempTxnId = :originalTempTxnId", 
                Long.class
            );
            query.setParameter("originalTempTxnId", originalTempTxnId);
            
            Long count = query.getSingleResult();
            return count > 0;
            
        } catch (Exception e) {
            logger.log("Error checking reversal existence: " + e.getMessage());
            return false;
        } finally {
            em.close();
        }
    }
    
    @Override
    public List<PosTransactionReversal> findByStatusIn(List<PosTransactionReversal.ReversalStatus> statuses) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<PosTransactionReversal> query = em.createQuery(
                "SELECT r FROM PosTransactionReversal r WHERE r.reversalStatus IN (:statuses)", 
                PosTransactionReversal.class
            );
            query.setParameter("statuses", statuses);
            
            return query.getResultList();
            
        } catch (Exception e) {
            logger.log("Error finding reversals by status: " + e.getMessage());
            return List.of();
        } finally {
            em.close();
        }
    }
    
    @Override
    public long countByStatusIn(List<PosTransactionReversal.ReversalStatus> statuses) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<Long> query = em.createQuery(
                "SELECT COUNT(r) FROM PosTransactionReversal r WHERE r.reversalStatus IN (:statuses)", 
                Long.class
            );
            query.setParameter("statuses", statuses);
            
            return query.getSingleResult();
            
        } catch (Exception e) {
            logger.log("Error counting reversals by status: " + e.getMessage());
            return 0;
        } finally {
            em.close();
        }
    }
    
    @Override
    public List<PosTransactionReversal> findReversalsForRetry(LocalDateTime currentTime) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<PosTransactionReversal> query = em.createQuery(
                "SELECT r FROM PosTransactionReversal r WHERE r.reversalStatus = :status " +
                "AND r.nextRetryTime <= :currentTime AND r.retryCount < r.maxRetryAttempts", 
                PosTransactionReversal.class
            );
            query.setParameter("status", PosTransactionReversal.ReversalStatus.RETRY_SCHEDULED);
            query.setParameter("currentTime", currentTime);
            
            return query.getResultList();
            
        } catch (Exception e) {
            logger.log("Error finding reversals for retry: " + e.getMessage());
            return List.of();
        } finally {
            em.close();
        }
    }
    
    @Override
    public List<PosTransactionReversal> findByBankTidAndBankMid(String bTid, String bMid) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<PosTransactionReversal> query = em.createQuery(
                "SELECT r FROM PosTransactionReversal r WHERE r.bTid = :bTid AND r.bMid = :bMid", 
                PosTransactionReversal.class
            );
            query.setParameter("bTid", bTid);
            query.setParameter("bMid", bMid);
            
            return query.getResultList();
            
        } catch (Exception e) {
            logger.log("Error finding reversals by bank IDs: " + e.getMessage());
            return List.of();
        } finally {
            em.close();
        }
    }
    
    @Override
    public long count() {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<Long> query = em.createQuery(
                "SELECT COUNT(r) FROM PosTransactionReversal r", 
                Long.class
            );
            return query.getSingleResult();
            
        } catch (Exception e) {
            logger.log("Error counting reversals: " + e.getMessage());
            return 0;
        } finally {
            em.close();
        }
    }
}