package de.cannamanage.api.controller;

import de.cannamanage.api.dto.event.*;
import de.cannamanage.api.security.StaffPermissionChecker;
import de.cannamanage.domain.entity.ClubEvent;
import de.cannamanage.domain.entity.EventRsvp;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.enums.RsvpStatus;
import de.cannamanage.domain.enums.StaffPermission;
import de.cannamanage.service.EventService;
import de.cannamanage.service.repository.EventRsvpRepository;
import de.cannamanage.service.repository.MemberRepository;
import jakarta.validation.Valid;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.util.*;

/**
 * REST controller for club event management.
 * Admin endpoints require MANAGE_INFO_BOARD permission.
 * Portal endpoints are accessible to authenticated members.
 */
@RestController
@RequestMapping("/api/v1")
public class EventController {

    private final EventService eventService;
    private final EventRsvpRepository rsvpRepository;
    private final MemberRepository memberRepository;
    private final StaffPermissionChecker permissionChecker;

    public EventController(EventService eventService,
                          EventRsvpRepository rsvpRepository,
                          MemberRepository memberRepository,
                          StaffPermissionChecker permissionChecker) {
        this.eventService = eventService;
        this.rsvpRepository = rsvpRepository;
        this.memberRepository = memberRepository;
        this.permissionChecker = permissionChecker;
    }

    // === Admin endpoints ===

    @PostMapping("/events")
    public ResponseEntity<EventResponse> createEvent(@Valid @RequestBody CreateEventRequest request,
                                                      @AuthenticationPrincipal UserDetails principal) {
        permissionChecker.requirePermission(principal, StaffPermission.MANAGE_INFO_BOARD);
        UUID clubId = TenantContext.getCurrentTenant();
        UUID userId = UUID.fromString(principal.getUsername());

        boolean postToInfoBoard = request.postToInfoBoard() == null || request.postToInfoBoard();

        ClubEvent event = eventService.createEvent(
                clubId, request.title(), request.description(), request.eventType(),
                request.startAt(), request.endAt(), request.location(), request.maxAttendees(),
                request.recurring(), request.recurrenceRule(), request.recurrenceEndDate(),
                userId, postToInfoBoard
        );

        return ResponseEntity.status(HttpStatus.CREATED).body(toResponse(event, null));
    }

    @GetMapping("/events")
    public ResponseEntity<List<EventResponse>> listEvents(
            @RequestParam Instant from,
            @RequestParam Instant to,
            @AuthenticationPrincipal UserDetails principal) {
        List<ClubEvent> events = eventService.listEvents(from, to);
        UUID userId = UUID.fromString(principal.getUsername());
        UUID memberId = getMemberIdForUser(userId);
        List<EventResponse> responses = events.stream()
                .map(e -> toResponse(e, memberId))
                .toList();
        return ResponseEntity.ok(responses);
    }

    @GetMapping("/events/{id}")
    public ResponseEntity<EventResponse> getEvent(@PathVariable UUID id,
                                                   @AuthenticationPrincipal UserDetails principal) {
        ClubEvent event = eventService.getEvent(id);
        UUID userId = UUID.fromString(principal.getUsername());
        UUID memberId = getMemberIdForUser(userId);
        return ResponseEntity.ok(toResponse(event, memberId));
    }

    @PutMapping("/events/{id}")
    public ResponseEntity<EventResponse> updateEvent(@PathVariable UUID id,
                                                      @Valid @RequestBody UpdateEventRequest request,
                                                      @AuthenticationPrincipal UserDetails principal) {
        permissionChecker.requirePermission(principal, StaffPermission.MANAGE_INFO_BOARD);
        ClubEvent event = eventService.updateEvent(id, request.title(), request.description(),
                request.eventType(), request.startAt(), request.endAt(), request.location(),
                request.maxAttendees(), request.recurring(), request.recurrenceRule(),
                request.recurrenceEndDate());
        return ResponseEntity.ok(toResponse(event, null));
    }

    @DeleteMapping("/events/{id}")
    public ResponseEntity<Void> cancelEvent(@PathVariable UUID id,
                                             @AuthenticationPrincipal UserDetails principal) {
        permissionChecker.requirePermission(principal, StaffPermission.MANAGE_INFO_BOARD);
        eventService.cancelEvent(id);
        return ResponseEntity.noContent().build();
    }

    @PostMapping("/events/{id}/rsvp")
    public ResponseEntity<?> rsvp(@PathVariable UUID id,
                                   @Valid @RequestBody RsvpRequest request,
                                   @AuthenticationPrincipal UserDetails principal) {
        UUID userId = UUID.fromString(principal.getUsername());
        UUID memberId = getMemberIdForUser(userId);
        if (memberId == null) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }

        try {
            EventRsvp rsvp = eventService.rsvp(id, memberId, request.status());
            return ResponseEntity.ok(Map.of(
                    "status", rsvp.getStatus(),
                    "respondedAt", rsvp.getRespondedAt()
            ));
        } catch (IllegalStateException e) {
            if ("EVENT_FULL".equals(e.getMessage())) {
                return ResponseEntity.status(HttpStatus.CONFLICT)
                        .body(Map.of("error", "EVENT_FULL", "message", "Veranstaltung ist ausgebucht"));
            }
            throw e;
        }
    }

    @GetMapping("/events/{id}/attendees")
    public ResponseEntity<List<RsvpResponse>> getAttendees(@PathVariable UUID id) {
        List<EventRsvp> rsvps = eventService.getAttendees(id);
        List<RsvpResponse> responses = rsvps.stream()
                .map(r -> {
                    String memberName = memberRepository.findById(r.getMemberId())
                            .map(m -> m.getFirstName() + " " + m.getLastName())
                            .orElse("Unknown");
                    return new RsvpResponse(r.getMemberId(), memberName, r.getStatus(), r.getRespondedAt());
                })
                .toList();
        return ResponseEntity.ok(responses);
    }

    @GetMapping("/events/{id}/ical")
    public ResponseEntity<String> downloadIcal(@PathVariable UUID id) {
        String ical = eventService.generateIcal(id);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"event.ics\"")
                .contentType(MediaType.parseMediaType("text/calendar"))
                .body(ical);
    }

    // === Portal endpoints ===

    @GetMapping("/portal/events")
    public ResponseEntity<List<EventResponse>> portalEvents(@AuthenticationPrincipal UserDetails principal) {
        UUID userId = UUID.fromString(principal.getUsername());
        UUID memberId = getMemberIdForUser(userId);
        List<ClubEvent> events = eventService.listUpcomingEvents(10);
        List<EventResponse> responses = events.stream()
                .map(e -> toResponse(e, memberId))
                .toList();
        return ResponseEntity.ok(responses);
    }

    @PostMapping("/portal/events/{id}/rsvp")
    public ResponseEntity<?> portalRsvp(@PathVariable UUID id,
                                         @Valid @RequestBody RsvpRequest request,
                                         @AuthenticationPrincipal UserDetails principal) {
        return rsvp(id, request, principal);
    }

    // === Helpers ===

    private EventResponse toResponse(ClubEvent event, UUID memberId) {
        Map<RsvpStatus, Long> counts = new HashMap<>();
        RsvpStatus myStatus = null;

        if (event.getId() != null) {
            try {
                counts = eventService.getAttendeeCounts(event.getId());
                if (memberId != null) {
                    myStatus = rsvpRepository.findByEventIdAndMemberId(event.getId(), memberId)
                            .map(EventRsvp::getStatus)
                            .orElse(null);
                }
            } catch (Exception e) {
                // Virtual expanded events may not have a DB id
            }
        }

        return new EventResponse(
                event.getId(),
                event.getTitle(),
                event.getDescription(),
                event.getEventType(),
                event.getStartAt(),
                event.getEndAt(),
                event.getLocation(),
                event.getMaxAttendees(),
                event.isRecurring(),
                event.getRecurrenceRule(),
                event.getRecurrenceEndDate(),
                event.getCreatedBy(),
                event.getCreatedAt(),
                counts,
                myStatus
        );
    }

    private UUID getMemberIdForUser(UUID userId) {
        return memberRepository.findByUserId(userId)
                .map(m -> m.getId())
                .orElse(null);
    }
}
