package com.example.volunteer.service;

import com.example.volunteer.model.Event;
import com.example.volunteer.model.Signup;
import com.example.volunteer.model.Volunteer;
import com.example.volunteer.repository.EventRepository;
import com.example.volunteer.repository.SignupRepository;
import com.example.volunteer.repository.VolunteerRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;

/**
 * ============================================================================
 * Service — 业务规则的唯一所在地
 * ============================================================================
 *
 * 【注意 / Note】
 * EN — The original paper says "the Controllers interact with the JPA Repositories … the
 *      Service Layer can be added in the future", so a Service is NOT required for the exam
 *      answer. This class exists because the sign-up operation touches two repositories and
 *      needs a transaction boundary.
 * 中 — 原卷说明 Controller 直接调 Repository、Service 层“以后再加”，所以考试答案不需要 Service。
 *      本类存在的原因：报名操作跨两个仓库，且需要事务边界。
 *
 * 【业务规则 / Business rules】
 * R1 活动必须存在            → EVENT_NOT_FOUND   (422)
 * R2 活动不能满员            → EVENT_FULL        (422)
 * R3 志愿者必须存在          → VOLUNTEER_NOT_FOUND (422, 假设)
 * R4 不能重复报名同一活动    → ALREADY_SIGNED_UP (422, 假设)
 * R5 时数必须大于 0          → INVALID_HOURS     (422, 假设)
 *
 * EN — Rule order is deliberate: existence first, then state, then duplicates, then data
 *      validity. Each rule is a single "if" with an early return.
 * 中 — 规则顺序是有意的：先存在性、再状态、再重复、最后数据合法性。每条规则一个 if、命中即返回。
 */
@Service
public class SignupService {

    private final EventRepository eventRepository;
    private final VolunteerRepository volunteerRepository;
    private final SignupRepository signupRepository;

    public SignupService(EventRepository eventRepository,
                         VolunteerRepository volunteerRepository,
                         SignupRepository signupRepository) {
        this.eventRepository = eventRepository;
        this.volunteerRepository = volunteerRepository;
        this.signupRepository = signupRepository;
    }

    /**
     * EN — Create a sign-up record for a volunteer.
     * 中 — 为一个志愿者创建报名记录。
     *
     * @param eventId     URL 里的活动 id
     * @param volunteerId 请求体里的志愿者 id
     * @param hours       服务时数
     */
    @Transactional
    public SignupResult signup(Long eventId, Long volunteerId, int hours) {

        // R5 数据合法性（先做最便宜的判断）
        if (hours <= 0) {
            return SignupResult.INVALID_HOURS;
        }

        // R1 活动存在
        Event event = eventRepository.findById(eventId).orElse(null);
        if (event == null) {
            return SignupResult.EVENT_NOT_FOUND;
        }

        // R2 未满员（报名人数 < 容量）
        if (event.getSignupCount() >= event.getCapacity()) {
            return SignupResult.EVENT_FULL;
        }

        // R3 志愿者存在
        Volunteer volunteer = volunteerRepository.findById(volunteerId).orElse(null);
        if (volunteer == null) {
            return SignupResult.VOLUNTEER_NOT_FOUND;
        }

        // R4 不重复报名
        if (signupRepository.existsByEventIdAndVolunteerId(eventId, volunteerId)) {
            return SignupResult.ALREADY_SIGNED_UP;
        }

        // 变更：创建报名记录
        Signup signup = new Signup();
        signup.setEvent(event);
        signup.setVolunteer(volunteer);
        signup.setHours(hours);
        signup.setSignupDate(LocalDate.now());
        signupRepository.save(signup);

        return SignupResult.CREATED;
    }
}
