package com.unicorn.hgzero.notification.domain;

import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.Comment;

import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * 알림 설정 Entity
 *
 * 사용자별 알림 설정 정보를 관리
 * 알림 채널, 유형별 활성화 여부, 방해 금지 시간대 설정
 *
 * @author 준호 (Backend Developer)
 * @version 1.0
 * @since 2025-10-23
 */
@Entity
@Table(name = "notification_settings", indexes = {
    @Index(name = "idx_setting_user_id", columnList = "user_id", unique = true)
})
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Comment("알림 설정 정보")
public class NotificationSetting {

    /**
     * 설정 고유 ID (사용자 ID와 동일)
     */
    @Id
    @Column(name = "user_id", length = 100, nullable = false)
    @Comment("사용자 ID")
    private String userId;

    /**
     * 이메일 알림 활성화 여부
     */
    @Column(name = "email_enabled", nullable = false)
    @Comment("이메일 알림 활성화")
    @Builder.Default
    private Boolean emailEnabled = true;

    /**
     * SMS 알림 활성화 여부
     */
    @Column(name = "sms_enabled", nullable = false)
    @Comment("SMS 알림 활성화")
    @Builder.Default
    private Boolean smsEnabled = false;

    /**
     * Push 알림 활성화 여부
     */
    @Column(name = "push_enabled", nullable = false)
    @Comment("Push 알림 활성화")
    @Builder.Default
    private Boolean pushEnabled = false;

    /**
     * 회의 초대 알림 활성화 여부
     */
    @Column(name = "invitation_enabled", nullable = false)
    @Comment("회의 초대 알림 활성화")
    @Builder.Default
    private Boolean invitationEnabled = true;

    /**
     * Todo 할당 알림 활성화 여부
     */
    @Column(name = "todo_assigned_enabled", nullable = false)
    @Comment("Todo 할당 알림 활성화")
    @Builder.Default
    private Boolean todoAssignedEnabled = true;

    /**
     * Todo 리마인더 알림 활성화 여부
     */
    @Column(name = "todo_reminder_enabled", nullable = false)
    @Comment("Todo 리마인더 알림 활성화")
    @Builder.Default
    private Boolean todoReminderEnabled = true;

    /**
     * 회의 리마인더 알림 활성화 여부
     */
    @Column(name = "meeting_reminder_enabled", nullable = false)
    @Comment("회의 리마인더 알림 활성화")
    @Builder.Default
    private Boolean meetingReminderEnabled = true;

    /**
     * 회의록 수정 알림 활성화 여부
     */
    @Column(name = "minutes_updated_enabled", nullable = false)
    @Comment("회의록 수정 알림 활성화")
    @Builder.Default
    private Boolean minutesUpdatedEnabled = true;

    /**
     * Todo 완료 알림 활성화 여부
     */
    @Column(name = "todo_completed_enabled", nullable = false)
    @Comment("Todo 완료 알림 활성화")
    @Builder.Default
    private Boolean todoCompletedEnabled = false;

    /**
     * 방해 금지 모드 활성화 여부
     */
    @Column(name = "dnd_enabled", nullable = false)
    @Comment("방해 금지 모드 활성화")
    @Builder.Default
    private Boolean dndEnabled = false;

    /**
     * 방해 금지 시작 시간 (예: 22:00)
     */
    @Column(name = "dnd_start_time")
    @Comment("방해 금지 시작 시간")
    private LocalTime dndStartTime;

    /**
     * 방해 금지 종료 시간 (예: 08:00)
     */
    @Column(name = "dnd_end_time")
    @Comment("방해 금지 종료 시간")
    private LocalTime dndEndTime;

    /**
     * 생성 일시
     */
    @Column(name = "created_at", nullable = false, updatable = false)
    @Comment("생성 일시")
    private LocalDateTime createdAt;

    /**
     * 수정 일시
     */
    @Column(name = "updated_at")
    @Comment("수정 일시")
    private LocalDateTime updatedAt;

    /**
     * 생성 전 초기화
     *
     * - createdAt: 현재 시각
     * - 기본값 설정
     */
    @PrePersist
    protected void onCreate() {
        if (this.createdAt == null) {
            this.createdAt = LocalDateTime.now();
        }
    }

    /**
     * 수정 전 업데이트
     *
     * - updatedAt: 현재 시각
     */
    @PreUpdate
    protected void onUpdate() {
        this.updatedAt = LocalDateTime.now();
    }

    /**
     * 알림 유형별 활성화 여부 확인
     *
     * @param notificationType 알림 유형
     * @return 활성화 여부
     */
    public boolean isNotificationTypeEnabled(Notification.NotificationType notificationType) {
        return switch (notificationType) {
            case INVITATION -> invitationEnabled;
            case TODO_ASSIGNED -> todoAssignedEnabled;
            case TODO_REMINDER -> todoReminderEnabled;
            case MEETING_REMINDER -> meetingReminderEnabled;
            case MINUTES_UPDATED -> minutesUpdatedEnabled;
            case TODO_COMPLETED -> todoCompletedEnabled;
        };
    }

    /**
     * 채널별 활성화 여부 확인
     *
     * @param channel 알림 채널
     * @return 활성화 여부
     */
    public boolean isChannelEnabled(Notification.NotificationChannel channel) {
        return switch (channel) {
            case EMAIL -> emailEnabled;
            case SMS -> smsEnabled;
            case PUSH -> pushEnabled;
        };
    }

    /**
     * 방해 금지 시간대 여부 확인
     *
     * @return 방해 금지 시간대 여부
     */
    public boolean isDoNotDisturbTime() {
        if (!dndEnabled || dndStartTime == null || dndEndTime == null) {
            return false;
        }

        LocalTime now = LocalTime.now();

        // 시작 시간이 종료 시간보다 이전인 경우 (예: 22:00 ~ 08:00)
        if (dndStartTime.isBefore(dndEndTime)) {
            return now.isAfter(dndStartTime) && now.isBefore(dndEndTime);
        }
        // 시작 시간이 종료 시간보다 이후인 경우 (자정을 넘는 경우)
        else {
            return now.isAfter(dndStartTime) || now.isBefore(dndEndTime);
        }
    }

    /**
     * 알림 발송 가능 여부 확인
     *
     * @param notificationType 알림 유형
     * @param channel 알림 채널
     * @return 발송 가능 여부
     */
    public boolean canSendNotification(
        Notification.NotificationType notificationType,
        Notification.NotificationChannel channel
    ) {
        // 채널 비활성화
        if (!isChannelEnabled(channel)) {
            return false;
        }

        // 알림 유형 비활성화
        if (!isNotificationTypeEnabled(notificationType)) {
            return false;
        }

        // 방해 금지 시간대
        if (isDoNotDisturbTime()) {
            return false;
        }

        return true;
    }
}
