package com.kt.event.eventservice.domain.entity;

import com.kt.event.common.entity.BaseTimeEntity;
import com.kt.event.eventservice.domain.enums.EventStatus;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import java.time.LocalDate;
import java.util.*;

/**
 * 이벤트 엔티티
 *
 * 이벤트의 전체 생명주기를 관리합니다.
 * - 생성, 수정, 배포, 종료
 * - AI 추천 및 이미지 관리
 * - 배포 채널 관리
 *
 * @author Event Service Team
 * @version 1.0.0
 * @since 2025-10-23
 */
@Entity
@Table(name = "events")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Event extends BaseTimeEntity {

    @Id
    @Column(name = "event_id", length = 50)
    private String eventId;

    @Column(name = "user_id", nullable = false, length = 50)
    private String userId;

    @Column(name = "store_id", nullable = false, length = 50)
    private String storeId;

    @Column(name = "event_name", length = 200)
    private String eventName;

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

    @Column(name = "objective", nullable = false, length = 100)
    private String objective;

    @Column(name = "start_date")
    private LocalDate startDate;

    @Column(name = "end_date")
    private LocalDate endDate;

    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false, length = 20)
    @Builder.Default
    private EventStatus status = EventStatus.DRAFT;

    @Column(name = "selected_image_id", length = 50)
    private String selectedImageId;

    @Column(name = "selected_image_url", length = 500)
    private String selectedImageUrl;

    @Column(name = "participants")
    @Builder.Default
    private Integer participants = 0;

    @Column(name = "target_participants")
    private Integer targetParticipants;

    @Column(name = "roi")
    @Builder.Default
    private Double roi = 0.0;

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(
        name = "event_channels",
        joinColumns = @JoinColumn(name = "event_id")
    )
    @Column(name = "channel", length = 50)
    @Fetch(FetchMode.SUBSELECT)
    @Builder.Default
    private List<String> channels = new ArrayList<>();

    @OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @Builder.Default
    private Set<GeneratedImage> generatedImages = new HashSet<>();

    @OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @Builder.Default
    private Set<AiRecommendation> aiRecommendations = new HashSet<>();

    // ==== 비즈니스 로직 ==== //

    /**
     * 이벤트명 수정
     */
    public void updateEventName(String eventName) {
        this.eventName = eventName;
    }

    /**
     * 설명 수정
     */
    public void updateDescription(String description) {
        this.description = description;
    }

    /**
     * 이벤트 기간 수정
     */
    public void updateEventPeriod(LocalDate startDate, LocalDate endDate) {
        if (startDate.isAfter(endDate)) {
            throw new IllegalArgumentException("시작일은 종료일보다 이전이어야 합니다.");
        }
        this.startDate = startDate;
        this.endDate = endDate;
    }

    /**
     * 이미지 선택
     */
    public void selectImage(String imageId, String imageUrl) {
        this.selectedImageId = imageId;
        this.selectedImageUrl = imageUrl;

        // 기존 선택 해제
        this.generatedImages.forEach(img -> img.setSelected(false));

        // 새로운 이미지 선택
        this.generatedImages.stream()
            .filter(img -> img.getImageId().equals(imageId))
            .findFirst()
            .ifPresent(img -> img.setSelected(true));
    }

    /**
     * 배포 채널 설정
     */
    public void updateChannels(List<String> channels) {
        this.channels.clear();
        this.channels.addAll(channels);
    }

    /**
     * 목표 참여자 수 설정
     */
    public void updateTargetParticipants(Integer targetParticipants) {
        if (targetParticipants != null && targetParticipants < 0) {
            throw new IllegalArgumentException("목표 참여자 수는 0 이상이어야 합니다.");
        }
        this.targetParticipants = targetParticipants;
    }

    /**
     * 참여자 수 증가
     */
    public void incrementParticipants() {
        this.participants = (this.participants == null ? 0 : this.participants) + 1;
        updateRoi();
    }

    /**
     * 참여자 수 직접 설정
     */
    public void updateParticipants(Integer participants) {
        if (participants != null && participants < 0) {
            throw new IllegalArgumentException("참여자 수는 0 이상이어야 합니다.");
        }
        this.participants = participants;
        updateRoi();
    }

    /**
     * ROI 계산 및 업데이트
     * ROI = (참여자 수 / 목표 참여자 수) * 100
     */
    private void updateRoi() {
        if (this.targetParticipants != null && this.targetParticipants > 0) {
            this.roi = ((double) (this.participants == null ? 0 : this.participants) / this.targetParticipants) * 100.0;
        } else {
            this.roi = 0.0;
        }
    }

    /**
     * ROI 직접 설정 (외부 계산값 사용)
     */
    public void updateRoi(Double roi) {
        if (roi != null && roi < 0) {
            throw new IllegalArgumentException("ROI는 0 이상이어야 합니다.");
        }
        this.roi = roi;
    }

    /**
     * 이벤트 배포 (상태 변경: DRAFT → PUBLISHED)
     */
    public void publish() {
        if (this.status != EventStatus.DRAFT) {
            throw new IllegalStateException("DRAFT 상태에서만 배포할 수 있습니다.");
        }

        // 필수 데이터 검증
        if (eventName == null || eventName.trim().isEmpty()) {
            throw new IllegalStateException("이벤트명을 입력해야 합니다.");
        }
        if (startDate == null || endDate == null) {
            throw new IllegalStateException("이벤트 기간을 설정해야 합니다.");
        }
        if (startDate.isAfter(endDate)) {
            throw new IllegalStateException("시작일은 종료일보다 이전이어야 합니다.");
        }
        // TODO: Frontend에서 selectedImageId 추적 구현 후 주석 제거
        // if (selectedImageId == null) {
        //     throw new IllegalStateException("이미지를 선택해야 합니다.");
        // }
        if (channels.isEmpty()) {
            throw new IllegalStateException("배포 채널을 선택해야 합니다.");
        }

        this.status = EventStatus.PUBLISHED;
    }

    /**
     * 이벤트 종료
     */
    public void end() {
        if (this.status != EventStatus.PUBLISHED) {
            throw new IllegalStateException("PUBLISHED 상태에서만 종료할 수 있습니다.");
        }
        this.status = EventStatus.ENDED;
    }

    /**
     * 생성된 이미지 추가
     */
    public void addGeneratedImage(GeneratedImage image) {
        this.generatedImages.add(image);
        image.setEvent(this);
    }

    /**
     * AI 추천 추가
     */
    public void addAiRecommendation(AiRecommendation recommendation) {
        this.aiRecommendations.add(recommendation);
        recommendation.setEvent(this);
    }

    /**
     * 수정 가능 여부 확인
     */
    public boolean isModifiable() {
        return this.status == EventStatus.DRAFT;
    }

    /**
     * 삭제 가능 여부 확인
     */
    public boolean isDeletable() {
        return this.status == EventStatus.DRAFT;
    }
}
