package org.jpos.tcpay.db.entity;

import lombok.Data;
import lombok.experimental.Accessors;

import javax.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Data
@Accessors(chain = true)
@Entity
@Table(name = "pos_transaction_reversal", 
       indexes = {
           @Index(name = "idx_reversal_btid_bmid", columnList = "b_tid,b_mid"),
           @Index(name = "idx_reversal_original_txn", columnList = "original_temp_txn_id"),
           @Index(name = "idx_reversal_status", columnList = "reversal_status"),
           @Index(name = "idx_reversal_created", columnList = "created_dateTime")
       })
public class PosTransactionReversal {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "original_temp_txn_id", nullable = false)
    private Long originalTempTxnId;

    @Column(name = "reversal_reason", length = 50, nullable = false)
    private String reversalReason;

    @Enumerated(EnumType.STRING)
    @Column(name = "reversal_status", length = 20, nullable = false)
    private ReversalStatus reversalStatus = ReversalStatus.PENDING;

    // Original transaction details for reversal
    @Column(name = "s_tid", length = 8)
    private String sTid;

    @Column(name = "s_mid", length = 15)
    private String sMid;

    @Column(name = "s_tid_stan", length = 6)
    private String sTidStan;

    @Column(name = "b_tid", length = 8)
    private String bTid;

    @Column(name = "b_mid", length = 15)
    private String bMid;

    @Column(name = "acquirer_id")
    private Long acquirerId;

    @Column(name = "b_tid_stan", length = 6)
    private String bTidStan;

    @Column(name = "original_mti", length = 4)
    private String originalMti;

    @Column(name = "reversal_mti", length = 4)
    private String reversalMti = "0400"; // Default reversal MTI

    @Column(name = "original_encrypted_pan", length = 40)
    private String originalEncryptedPan;

    @Column(name = "original_encrypted_expiry_date", length = 40)
    private String originalEncryptedExpiryDate;

    @Column(name = "original_proc_code", length = 6)
    private String originalProcCode;

    @Column(name = "original_amount", precision = 12, scale = 2)
    private BigDecimal originalAmount;

    @Column(name = "original_stan", length = 6)
    private String originalStan;

    @Column(name = "original_time", length = 6)
    private String originalTime;

    @Column(name = "original_date", length = 8)
    private String originalDate;

    @Column(name = "original_entry_mode", length = 3)
    private String originalEntryMode;

    @Column(name = "original_pan_seq", length = 3)
    private String originalPanSequence;

    @Column(name = "original_reference_no", length = 12)
    private String originalReferenceNo;

    @Column(name = "original_currency_code", length = 3)
    private String originalCurrencyCode;

    @Column(name = "original_batch_no", length = 3)
    private String originalBatchNo;

    // Reversal request/response data
    @Column(name = "reversal_request", columnDefinition = "TEXT")
    private String reversalRequest;

    @Column(name = "reversal_response", columnDefinition = "TEXT")
    private String reversalResponse;

    @Column(name = "reversal_response_code", length = 2)
    private String reversalResponseCode;

    @Column(name = "reversal_reference_no", length = 12)
    private String reversalReferenceNo;

    @Column(name = "retry_count", nullable = false)
    private int retryCount = 0;

    @Column(name = "max_retry_attempts", nullable = false)
    private int maxRetryAttempts = 3;

    @Column(name = "next_retry_time")
    private LocalDateTime nextRetryTime;

    @Column(name = "created_dateTime", nullable = false)
    private LocalDateTime createdDateTime;

    @Column(name = "initiated_dateTime")
    private LocalDateTime initiatedDateTime;

    @Column(name = "completed_dateTime")
    private LocalDateTime completedDateTime;

    @Column(name = "updated_dateTime")
    private LocalDateTime updatedDateTime;

    @Column(name = "error_message", length = 255)
    private String errorMessage;

    @Column(name = "metadata", columnDefinition = "TEXT")
    private String metadata;

    @PrePersist
    protected void onCreate() {
        createdDateTime = LocalDateTime.now();
        updatedDateTime = LocalDateTime.now();
        if (reversalStatus == null) {
            reversalStatus = ReversalStatus.PENDING;
        }
    }

    @PreUpdate
    protected void onUpdate() {
        updatedDateTime = LocalDateTime.now();
    }

    /**
     * Status progression for reversal transactions
     */
    public enum ReversalStatus {
        PENDING,           // Reversal created but not yet sent
        SENT,             // Reversal message sent to bank
        COMPLETED,        // Reversal successful
        FAILED,           // Reversal failed
        RETRY_SCHEDULED,  // Scheduled for retry
        MAX_RETRIES_EXCEEDED, // Failed after max retries
        MANUAL_REVIEW     // Requires manual intervention
    }

    /**
     * Common reversal reasons
     */
    public static final String REASON_STALE_TRANSACTION = "STALE_TRANSACTION_CLEANUP";
    public static final String REASON_RESPONSE_TIMEOUT = "RESPONSE_TIMEOUT";
    public static final String REASON_CONNECTION_LOST = "CONNECTION_LOST_RECOVERY";
    public static final String REASON_SYSTEM_STARTUP = "SYSTEM_STARTUP_CLEANUP";
    public static final String REASON_DATABASE_ERROR = "DATABASE_ERROR_RECOVERY";
    public static final String REASON_MANUAL_CLEANUP = "MANUAL_CLEANUP";
}