package com.example.dateplanner.services;

import com.example.dateplanner.dto.SubmitApplicationDto;
import com.example.dateplanner.models.entities.EventApplication;
import com.example.dateplanner.repositories.EventApplicationRepository;
import com.example.dateplanner.repositories.TennisEventRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Mono;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor
public class ApplicationService {

    private final TurnstileService turnstileService;
    private final TennisEventRepository eventRepository;
    private final EventApplicationRepository applicationRepository;
    private final EmailService emailService;

    // ── Подача заявки ─────────────────────────────────────────────────────────

    public Mono<EventApplication> submit(UUID eventId, SubmitApplicationDto dto) {
        return turnstileService.verify(dto.getCfTurnstileResponse())
                .flatMap(valid -> {
                    if (!valid) {
                        return Mono.error(new ResponseStatusException(
                                HttpStatus.BAD_REQUEST, "Капча не пройдена. Попробуйте снова."));
                    }
                    return eventRepository.findById(eventId);
                })
                .switchIfEmpty(Mono.error(new ResponseStatusException(
                        HttpStatus.NOT_FOUND, "Мероприятие не найдено")))
                .flatMap(event -> {
                    if (Boolean.FALSE.equals(event.getRegistrationOpen())) {
                        return Mono.error(new ResponseStatusException(
                                HttpStatus.FORBIDDEN, "Регистрация на это мероприятие закрыта"));
                    }
                    EventApplication app = new EventApplication();
                    app.setEventUuid(event.getUuid());
                    app.setClubUuid(event.getClubUuid());
                    app.setFullName(dto.getFullName());
                    app.setEmail(dto.getEmail());
                    if (dto.getBirthDate() != null && !dto.getBirthDate().isBlank()) {
                        try {
                            app.setBirthDate(LocalDate.parse(dto.getBirthDate()));
                        } catch (Exception ignored) {}
                    }
                    app.setGender(dto.getGender());
                    app.setPhone(dto.getPhone());
                    app.setRatingPoints(dto.getRatingPoints());
                    app.setStatus("PENDING");
                    app.setCreatedAt(LocalDateTime.now());
                    app.setUpdatedAt(LocalDateTime.now());

                    return applicationRepository.save(app)
                            .flatMap(saved ->
                                    sendConfirmationEmail(saved, event.getTitle())
                                            .thenReturn(saved));
                });
    }

    // ── Одобрение ─────────────────────────────────────────────────────────────

    public Mono<EventApplication> approve(UUID appId) {
        return applicationRepository.findById(appId)
                .switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, "Заявка не найдена")))
                .flatMap(app -> {
                    if ("APPROVED".equals(app.getStatus())) {
                        return Mono.just(app);
                    }
                    app.setStatus("APPROVED");
                    app.setUpdatedAt(LocalDateTime.now());
                    return applicationRepository.save(app);
                })
                .flatMap(saved ->
                        eventRepository.findById(saved.getEventUuid())
                                .flatMap(event -> {
                                    int current = event.getCurrentParticipants() != null
                                            ? event.getCurrentParticipants() : 0;
                                    event.setCurrentParticipants(current + 1);
                                    return eventRepository.save(event).map(e -> e.getTitle());
                                })
                                .defaultIfEmpty("Мероприятие")
                                .flatMap(title -> sendApprovalEmail(saved, title).thenReturn(saved))
                );
    }

    // ── Отклонение ────────────────────────────────────────────────────────────

    public Mono<EventApplication> reject(UUID appId, String reason) {
        return applicationRepository.findById(appId)
                .switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, "Заявка не найдена")))
                .flatMap(app -> {
                    app.setStatus("REJECTED");
                    app.setRejectionReason(reason);
                    app.setUpdatedAt(LocalDateTime.now());
                    return applicationRepository.save(app);
                })
                .flatMap(saved ->
                        eventRepository.findById(saved.getEventUuid())
                                .map(e -> e.getTitle())
                                .defaultIfEmpty("Мероприятие")
                                .flatMap(title -> sendRejectionEmail(saved, title, reason).thenReturn(saved))
                );
    }

    // ── Письма ────────────────────────────────────────────────────────────────

    private Mono<Void> sendConfirmationEmail(EventApplication app, String eventTitle) {
        String subject = "Заявка на участие в мероприятии «" + eventTitle + "» принята";
        String birthDateStr = app.getBirthDate() != null
                ? app.getBirthDate().format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))
                : "не указана";

        String body = """
                <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
                  <div style="background:linear-gradient(135deg,#2ecc71,#27ae60);padding:30px;border-radius:12px 12px 0 0;text-align:center">
                    <h1 style="color:#fff;margin:0;font-size:1.8rem">TennisHub</h1>
                    <p style="color:rgba(255,255,255,0.9);margin:6px 0 0">Заявка на участие принята</p>
                  </div>
                  <div style="background:#fff;padding:30px;border:1px solid #e0e0e0;border-radius:0 0 12px 12px">
                    <p style="font-size:1.1rem">Уважаемый(ая) <b>%s</b>,</p>
                    <p>Ваша заявка на участие в мероприятии <b>«%s»</b> успешно зарегистрирована и ожидает рассмотрения организаторами.</p>
                    <div style="background:#f8f9fa;border-radius:8px;padding:20px;margin:20px 0">
                      <h3 style="margin:0 0 12px;color:#2c3e50">Данные заявки:</h3>
                      <table style="width:100%%">
                        <tr><td style="color:#666;padding:4px 0">ФИО:</td><td style="font-weight:600">%s</td></tr>
                        <tr><td style="color:#666;padding:4px 0">Email:</td><td>%s</td></tr>
                        <tr><td style="color:#666;padding:4px 0">Телефон:</td><td>%s</td></tr>
                        <tr><td style="color:#666;padding:4px 0">Дата рождения:</td><td>%s</td></tr>
                        <tr><td style="color:#666;padding:4px 0">Пол:</td><td>%s</td></tr>
                        <tr><td style="color:#666;padding:4px 0">Рейтинговые очки:</td><td>%s</td></tr>
                      </table>
                    </div>
                    <p style="color:#666;font-size:0.9rem">Организаторы свяжутся с вами по указанному email или телефону.</p>
                  </div>
                </div>
                """.formatted(
                app.getFullName(), eventTitle,
                app.getFullName(), app.getEmail(),
                app.getPhone() != null ? app.getPhone() : "не указан",
                birthDateStr,
                app.getGender() != null ? app.getGender() : "не указан",
                app.getRatingPoints() != null ? app.getRatingPoints() : "не указаны"
        );

        return emailService.send(app.getEmail(), subject, body)
                .doOnError(e -> log.error("Failed to send confirmation email to {}: {}", app.getEmail(), e.getMessage()))
                .onErrorResume(e -> Mono.empty());
    }

    private Mono<Void> sendApprovalEmail(EventApplication app, String eventTitle) {
        String subject = "Ваша заявка на участие в «" + eventTitle + "» одобрена!";
        String body = """
                <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
                  <div style="background:linear-gradient(135deg,#2ecc71,#27ae60);padding:30px;border-radius:12px 12px 0 0;text-align:center">
                    <h1 style="color:#fff;margin:0;font-size:1.8rem">TennisHub</h1>
                    <p style="color:rgba(255,255,255,0.9);margin:6px 0 0">Заявка одобрена</p>
                  </div>
                  <div style="background:#fff;padding:30px;border:1px solid #e0e0e0;border-radius:0 0 12px 12px">
                    <div style="text-align:center;margin-bottom:24px">
                      <div style="width:64px;height:64px;background:#d1f2e8;border-radius:50%%;display:inline-flex;align-items:center;justify-content:center;font-size:2rem">✅</div>
                    </div>
                    <p style="font-size:1.1rem">Уважаемый(ая) <b>%s</b>,</p>
                    <p>Поздравляем! Ваша заявка на участие в мероприятии <b>«%s»</b> была <b style="color:#27ae60">одобрена</b> организаторами.</p>
                    <p>Ждём вас на мероприятии! Если у вас возникнут вопросы, свяжитесь с организаторами.</p>
                    <p style="color:#666;font-size:0.9rem;margin-top:20px">С уважением,<br>Команда TennisHub</p>
                  </div>
                </div>
                """.formatted(app.getFullName(), eventTitle);

        return emailService.send(app.getEmail(), subject, body)
                .doOnError(e -> log.error("Failed to send approval email to {}: {}", app.getEmail(), e.getMessage()))
                .onErrorResume(e -> Mono.empty());
    }

    private Mono<Void> sendRejectionEmail(EventApplication app, String eventTitle, String reason) {
        String subject = "Решение по заявке на участие в «" + eventTitle + "»";
        String reasonBlock = (reason != null && !reason.isBlank())
                ? "<div style=\"background:#fff3f3;border-left:4px solid #e74c3c;border-radius:4px;padding:14px 18px;margin:16px 0\">"
                  + "<b>Причина:</b> " + reason + "</div>"
                : "";
        String body = """
                <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
                  <div style="background:linear-gradient(135deg,#c0392b,#e74c3c);padding:30px;border-radius:12px 12px 0 0;text-align:center">
                    <h1 style="color:#fff;margin:0;font-size:1.8rem">TennisHub</h1>
                    <p style="color:rgba(255,255,255,0.9);margin:6px 0 0">Решение по заявке</p>
                  </div>
                  <div style="background:#fff;padding:30px;border:1px solid #e0e0e0;border-radius:0 0 12px 12px">
                    <div style="text-align:center;margin-bottom:24px">
                      <div style="width:64px;height:64px;background:#fde8e8;border-radius:50%%;display:inline-flex;align-items:center;justify-content:center;font-size:2rem">❌</div>
                    </div>
                    <p style="font-size:1.1rem">Уважаемый(ая) <b>%s</b>,</p>
                    <p>К сожалению, ваша заявка на участие в мероприятии <b>«%s»</b> была <b style="color:#e74c3c">отклонена</b> организаторами.</p>
                    %s
                    <p>Если у вас есть вопросы, пожалуйста, свяжитесь с организаторами напрямую.</p>
                    <p style="color:#666;font-size:0.9rem;margin-top:20px">С уважением,<br>Команда TennisHub</p>
                  </div>
                </div>
                """.formatted(app.getFullName(), eventTitle, reasonBlock);

        return emailService.send(app.getEmail(), subject, body)
                .doOnError(e -> log.error("Failed to send rejection email to {}: {}", app.getEmail(), e.getMessage()))
                .onErrorResume(e -> Mono.empty());
    }
}
