package com.rit.canteen.sales.model;

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

/**
 * Tracks a Razorpay payment from creation through fulfillment.
 * Ensures order placement / wallet credit only happens after verified payment,
 * and is idempotent across client retries and webhooks.
 */
@Entity
@Table(name = "payment_sessions", indexes = {
    @Index(name = "idx_payment_sessions_user", columnList = "user_id"),
    @Index(name = "idx_payment_sessions_status", columnList = "status")
})
public class PaymentSession {

    public enum Purpose {
        ORDER,
        WALLET_TOPUP
    }

    public enum Status {
        CREATED,
        PAID,
        FULFILLED,
        FULFILLED_AS_CREDIT,
        FAILED,
        EXPIRED
    }

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

    @Column(name = "user_id", nullable = false)
    private Long userId;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 32)
    private Purpose purpose;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 32)
    private Status status = Status.CREATED;

    /** Amount in INR (rupees), not paise */
    @Column(nullable = false, precision = 12, scale = 2)
    private BigDecimal amountInr;

    @Column(nullable = false, length = 8)
    private String currency = "INR";

    @Column(name = "razorpay_order_id", nullable = false, unique = true, length = 64)
    private String razorpayOrderId;

    @Column(name = "razorpay_payment_id", unique = true, length = 64)
    private String razorpayPaymentId;

    @Column(name = "razorpay_signature", length = 256)
    private String razorpaySignature;

    /** Serialized cart/order payload for ORDER purpose (JSON text) */
    @Column(name = "order_payload", columnDefinition = "TEXT")
    private String orderPayload;

    @Column(name = "fulfillment_order_number", length = 64)
    private String fulfillmentOrderNumber;

    @Column(name = "fulfillment_display_id", length = 32)
    private String fulfillmentDisplayId;

    @Column(name = "failure_reason", length = 512)
    private String failureReason;

    @Column(name = "created_at", nullable = false)
    private LocalDateTime createdAt;

    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;

    @Column(name = "fulfilled_at")
    private LocalDateTime fulfilledAt;

    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        if (createdAt == null) createdAt = now;
        if (updatedAt == null) updatedAt = now;
        if (status == null) status = Status.CREATED;
        if (currency == null) currency = "INR";
    }

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

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public Long getUserId() { return userId; }
    public void setUserId(Long userId) { this.userId = userId; }

    public Purpose getPurpose() { return purpose; }
    public void setPurpose(Purpose purpose) { this.purpose = purpose; }

    public Status getStatus() { return status; }
    public void setStatus(Status status) { this.status = status; }

    public BigDecimal getAmountInr() { return amountInr; }
    public void setAmountInr(BigDecimal amountInr) { this.amountInr = amountInr; }

    public String getCurrency() { return currency; }
    public void setCurrency(String currency) { this.currency = currency; }

    public String getRazorpayOrderId() { return razorpayOrderId; }
    public void setRazorpayOrderId(String razorpayOrderId) { this.razorpayOrderId = razorpayOrderId; }

    public String getRazorpayPaymentId() { return razorpayPaymentId; }
    public void setRazorpayPaymentId(String razorpayPaymentId) { this.razorpayPaymentId = razorpayPaymentId; }

    public String getRazorpaySignature() { return razorpaySignature; }
    public void setRazorpaySignature(String razorpaySignature) { this.razorpaySignature = razorpaySignature; }

    public String getOrderPayload() { return orderPayload; }
    public void setOrderPayload(String orderPayload) { this.orderPayload = orderPayload; }

    public String getFulfillmentOrderNumber() { return fulfillmentOrderNumber; }
    public void setFulfillmentOrderNumber(String fulfillmentOrderNumber) { this.fulfillmentOrderNumber = fulfillmentOrderNumber; }

    public String getFulfillmentDisplayId() { return fulfillmentDisplayId; }
    public void setFulfillmentDisplayId(String fulfillmentDisplayId) { this.fulfillmentDisplayId = fulfillmentDisplayId; }

    public String getFailureReason() { return failureReason; }
    public void setFailureReason(String failureReason) { this.failureReason = failureReason; }

    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }

    public LocalDateTime getUpdatedAt() { return updatedAt; }
    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }

    public LocalDateTime getFulfilledAt() { return fulfilledAt; }
    public void setFulfilledAt(LocalDateTime fulfilledAt) { this.fulfilledAt = fulfilledAt; }
}
