package com.kt.event.participation.domain.participant;

import com.kt.event.common.entity.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.*;

/**
 * 이벤트 참여자 엔티티
 *
 * @author Digital Garage Team
 * @since 2025-01-24
 */
@Entity
@Table(name = "participants",
    indexes = {
        @Index(name = "idx_participant_event_id", columnList = "event_id"),
        @Index(name = "idx_participant_event_phone", columnList = "event_id, phone_number")

    },
    uniqueConstraints = {
        @UniqueConstraint(name = "uk_event_phone", columnNames = {"event_id", "phone_number"})
    }
)
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Participant extends BaseTimeEntity {

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

    /**
     * 참여자 ID (외부 노출용)
     * 예: prt_20250123_001
     */
    @Column(name = "participant_id", nullable = false, unique = true, length = 50)
    private String participantId;

    /**
     * 이벤트 ID
     * Event Service의 이벤트 식별자
     */
    @Column(name = "event_id", nullable = false, length = 50)
    private String eventId;

    /**
     * 참여자 이름
     */
    @Column(name = "name", nullable = false, length = 50)
    private String name;

    /**
     * 참여자 전화번호
     * 중복 참여 체크 키로 사용
     */
    @Column(name = "phone_number", nullable = false, length = 20)
    private String phoneNumber;

    /**
     * 참여자 이메일
     */
    @Column(name = "email", length = 100)
    private String email;

    /**
     * 참여 채널
     * 기본값: SNS
     * TODO: 기존 데이터 마이그레이션 후 nullable = false로 변경
     */
    @Column(name = "channel", length = 20, nullable = true)
    private String channel;

    /**
     * 매장 방문 여부
     * true일 경우 보너스 응모권 부여
     */
    @Column(name = "store_visited", nullable = false)
    private Boolean storeVisited;

    /**
     * 보너스 응모권 수
     * 기본 1, 매장 방문 시 +1
     */
    @Column(name = "bonus_entries", nullable = false)
    private Integer bonusEntries;

    /**
     * 마케팅 정보 수신 동의
     */
    @Column(name = "agree_marketing", nullable = false)
    private Boolean agreeMarketing;

    /**
     * 개인정보 수집 및 이용 동의 (필수)
     */
    @Column(name = "agree_privacy", nullable = false)
    private Boolean agreePrivacy;

    /**
     * 당첨 여부
     */
    @Column(name = "is_winner", nullable = false)
    private Boolean isWinner;

    /**
     * 당첨 순위 (당첨자일 경우)
     */
    @Column(name = "winner_rank")
    private Integer winnerRank;

    /**
     * 당첨 일시
     */
    @Column(name = "won_at")
    private java.time.LocalDateTime wonAt;

    /**
     * 참여자 ID 생성
     *
     * @param eventId 이벤트 ID
     * @param sequenceNumber 순번
     * @return 생성된 참여자 ID
     */
    public static String generateParticipantId(String eventId, Long sequenceNumber) {
        // eventId가 "evt_YYYYMMDD_XXX" 형식인 경우
        if (eventId != null && eventId.length() >= 16 && eventId.startsWith("evt_")) {
            String dateTime = eventId.substring(4, 12); // "20250124"
            return String.format("prt_%s_%03d", dateTime, sequenceNumber);
        }

        // 그 외의 경우 (짧은 eventId 등): 현재 날짜 사용
        String dateTime = java.time.LocalDate.now().format(
            java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd"));
        return String.format("prt_%s_%03d", dateTime, sequenceNumber);
    }

    /**
     * 보너스 응모권 계산
     *
     * @param storeVisited 매장 방문 여부
     * @return 보너스 응모권 수
     */
    public static Integer calculateBonusEntries(Boolean storeVisited) {
        return storeVisited ? 5 : 1;
    }

    /**
     * 당첨자로 설정
     *
     * @param rank 당첨 순위
     */
    public void markAsWinner(Integer rank) {
        this.isWinner = true;
        this.winnerRank = rank;
        this.wonAt = java.time.LocalDateTime.now();
    }

    /**
     * 참여자 생성 전 유효성 검증
     */
    @PrePersist
    public void prePersist() {
        if (this.agreePrivacy == null || !this.agreePrivacy) {
            throw new IllegalStateException("개인정보 수집 및 이용 동의는 필수입니다");
        }
        if (this.bonusEntries == null) {
            this.bonusEntries = calculateBonusEntries(this.storeVisited);
        }
        if (this.isWinner == null) {
            this.isWinner = false;
        }
        if (this.agreeMarketing == null) {
            this.agreeMarketing = false;
        }
        if (this.channel == null || this.channel.isBlank()) {
            this.channel = "SNS";
        }
    }
}
