package org.jpos.tcpay.db.repository;

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

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

/**
 * JPA implementation of PosFailedTransactionRepository
 * Uses EntityManager for all database operations
 */
public class PosFailedTransactionRepositoryImpl implements PosFailedTransactionRepository {
    
    private final EntityManagerFactory emf;
    private final AppLogger logger = new AppLogger();
    
    public PosFailedTransactionRepositoryImpl(EntityManagerFactory emf) {
        this.emf = emf;
    }
    
    @Override
    public PosFailedTransaction save(PosFailedTransaction failedTransaction) {
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        
        try {
            tx.begin();
            
            if (failedTransaction.getId() == null) {
                em.persist(failedTransaction);
            } else {
                failedTransaction = em.merge(failedTransaction);
            }
            
            tx.commit();
            logger.log("Saved failed transaction: " + failedTransaction.getId());
            return failedTransaction;
            
        } catch (Exception e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            logger.log("Error saving failed transaction: " + e.getMessage());
            throw new RuntimeException("Failed to save failed transaction", e);
        } finally {
            em.close();
        }
    }
    
    @Override
    public Optional<PosFailedTransaction> findById(Long id) {
        EntityManager em = emf.createEntityManager();
        try {
            PosFailedTransaction transaction = em.find(PosFailedTransaction.class, id);
            return Optional.ofNullable(transaction);
        } catch (Exception e) {
            logger.log("Error finding failed transaction by ID: " + e.getMessage());
            return Optional.empty();
        } finally {
            em.close();
        }
    }
    
    @Override
    public List<PosFailedTransaction> findByBankTidAndBankMid(String bTid, String bMid) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<PosFailedTransaction> query = em.createQuery(
                "SELECT t FROM PosFailedTransaction t WHERE t.bTid = :bTid AND t.bMid = :bMid", 
                PosFailedTransaction.class
            );
            query.setParameter("bTid", bTid);
            query.setParameter("bMid", bMid);
            
            return query.getResultList();
            
        } catch (Exception e) {
            logger.log("Error finding failed transactions by bank IDs: " + e.getMessage());
            return new ArrayList<>();
        } finally {
            em.close();
        }
    }
    
    @Override
    public long countTransactionsSince(LocalDateTime since) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<Long> query = em.createQuery(
                "SELECT COUNT(t) FROM PosFailedTransaction t WHERE t.createdDateTime >= :since", 
                Long.class
            );
            query.setParameter("since", since);
            
            return query.getSingleResult();
            
        } catch (Exception e) {
            logger.log("Error counting failed transactions since: " + e.getMessage());
            return 0;
        } finally {
            em.close();
        }
    }
    
    @Override
    public List<PosFailedTransaction> findByResponseCode(String responseCode) {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<PosFailedTransaction> query = em.createQuery(
                "SELECT t FROM PosFailedTransaction t WHERE t.responseCode = :responseCode", 
                PosFailedTransaction.class
            );
            query.setParameter("responseCode", responseCode);
            
            return query.getResultList();
            
        } catch (Exception e) {
            logger.log("Error finding failed transactions by response code: " + e.getMessage());
            return new ArrayList<>();
        } finally {
            em.close();
        }
    }
    
    @Override
    public long count() {
        EntityManager em = emf.createEntityManager();
        try {
            TypedQuery<Long> query = em.createQuery(
                "SELECT COUNT(t) FROM PosFailedTransaction t", 
                Long.class
            );
            return query.getSingleResult();
            
        } catch (Exception e) {
            logger.log("Error counting failed transactions: " + e.getMessage());
            return 0;
        } finally {
            em.close();
        }
    }
}