package de.cannamanage.api.controller;

import de.cannamanage.api.dto.member.CreateMemberRequest;
import de.cannamanage.api.dto.member.MemberResponse;
import de.cannamanage.api.dto.member.UpdateMemberRequest;
import de.cannamanage.api.dto.prevention.PreventionDataResponse;
import de.cannamanage.api.dto.prevention.Under21MemberResponse;
import de.cannamanage.domain.entity.Member;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.enums.MemberStatus;
import de.cannamanage.service.PreventionOfficerService;
import de.cannamanage.service.repository.MemberRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Period;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/api/v1/members")
@RequiredArgsConstructor
@Tag(name = "Members", description = "Club member management")
public class MemberController {

    private final MemberRepository memberRepository;
    private final PreventionOfficerService preventionOfficerService;

    @GetMapping
    @Operation(summary = "List all members", description = "Returns all members for the current tenant")
    @PreAuthorize("hasRole('ADMIN') or @staffPermissions.has(authentication, T(de.cannamanage.domain.enums.StaffPermission).VIEW_MEMBER_LIST)")
    public ResponseEntity<List<MemberResponse>> listMembers() {
        List<MemberResponse> members = memberRepository.findAll().stream()
                .map(this::toResponse)
                .toList();
        return ResponseEntity.ok(members);
    }

    @GetMapping("/{id}")
    @Operation(summary = "Get member by ID")
    @PreAuthorize("hasRole('ADMIN') or hasRole('MEMBER') or @staffPermissions.has(authentication, T(de.cannamanage.domain.enums.StaffPermission).VIEW_MEMBER_LIST)")
    public ResponseEntity<MemberResponse> getMember(@PathVariable UUID id) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Member not found"));
        return ResponseEntity.ok(toResponse(member));
    }

    @PostMapping
    @Operation(summary = "Create a new member")
    @PreAuthorize("hasRole('ADMIN') or @staffPermissions.has(authentication, T(de.cannamanage.domain.enums.StaffPermission).ADD_MEMBER)")
    public ResponseEntity<MemberResponse> createMember(@Valid @RequestBody CreateMemberRequest request) {
        Member member = new Member();
        member.setFirstName(request.firstName());
        member.setLastName(request.lastName());
        member.setEmail(request.email());
        member.setDateOfBirth(request.dateOfBirth());
        member.setMembershipDate(request.membershipDate());
        member.setMembershipNumber(request.membershipNumber());
        member.setClubId(TenantContext.getCurrentTenant()); // club == tenant for MVP
        member.setUnder21(isUnder21(request.dateOfBirth()));

        Member saved = memberRepository.save(member);
        return ResponseEntity.status(HttpStatus.CREATED).body(toResponse(saved));
    }

    @PutMapping("/{id}")
    @Operation(summary = "Update a member")
    @PreAuthorize("hasRole('ADMIN') or @staffPermissions.has(authentication, T(de.cannamanage.domain.enums.StaffPermission).ADD_MEMBER)")
    public ResponseEntity<MemberResponse> updateMember(@PathVariable UUID id,
                                                       @Valid @RequestBody UpdateMemberRequest request) {
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Member not found"));

        if (request.firstName() != null) member.setFirstName(request.firstName());
        if (request.lastName() != null) member.setLastName(request.lastName());
        if (request.email() != null) member.setEmail(request.email());
        if (request.dateOfBirth() != null) {
            member.setDateOfBirth(request.dateOfBirth());
            member.setUnder21(isUnder21(request.dateOfBirth()));
        }
        if (request.membershipNumber() != null) member.setMembershipNumber(request.membershipNumber());
        if (request.status() != null) member.setStatus(MemberStatus.valueOf(request.status()));

        Member saved = memberRepository.save(member);
        return ResponseEntity.ok(toResponse(saved));
    }

    @GetMapping("/under-21")
    @Operation(summary = "List under-21 members", description = "Returns all under-21 members with current month distribution data. Prevention officer or ADMIN access required.")
    @PreAuthorize("hasRole('ADMIN') or @preventionOfficer.check(authentication)")
    public ResponseEntity<List<Under21MemberResponse>> getUnder21Members() {
        UUID tenantId = TenantContext.getCurrentTenant();
        List<Member> under21Members = preventionOfficerService.getUnder21Members(tenantId);

        List<Under21MemberResponse> response = under21Members.stream()
                .map(m -> {
                    int age = preventionOfficerService.calculateAge(m.getDateOfBirth());
                    long distCount = preventionOfficerService.countCurrentMonthDistributions(tenantId, m.getId());
                    BigDecimal gramsUsed = preventionOfficerService.sumCurrentMonthGrams(tenantId, m.getId());
                    BigDecimal limit = preventionOfficerService.getMonthlyLimit(m);
                    BigDecimal remaining = limit.subtract(gramsUsed).max(BigDecimal.ZERO);
                    String quotaStatus = remaining.compareTo(BigDecimal.ZERO) > 0 ? "OK" : "EXHAUSTED";
                    return new Under21MemberResponse(
                            m.getId(), m.getFirstName(), m.getLastName(),
                            age, m.getDateOfBirth(), distCount,
                            gramsUsed, limit, quotaStatus
                    );
                })
                .toList();
        return ResponseEntity.ok(response);
    }

    @GetMapping("/{id}/prevention-data")
    @Operation(summary = "Get prevention data for a member", description = "Returns prevention-relevant data for a specific member. Prevention officer or ADMIN access required.")
    @PreAuthorize("hasRole('ADMIN') or @preventionOfficer.check(authentication)")
    public ResponseEntity<PreventionDataResponse> getPreventionData(@PathVariable UUID id) {
        UUID tenantId = TenantContext.getCurrentTenant();
        Member member = memberRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Member not found"));

        int age = preventionOfficerService.calculateAge(member.getDateOfBirth());
        long distCount = preventionOfficerService.countCurrentMonthDistributions(tenantId, member.getId());
        BigDecimal gramsUsed = preventionOfficerService.sumCurrentMonthGrams(tenantId, member.getId());
        BigDecimal limit = preventionOfficerService.getMonthlyLimit(member);
        BigDecimal remaining = limit.subtract(gramsUsed).max(BigDecimal.ZERO);

        return ResponseEntity.ok(new PreventionDataResponse(
                member.getId(),
                member.getFirstName() + " " + member.getLastName(),
                member.isUnder21(),
                age,
                distCount,
                gramsUsed,
                limit,
                remaining
        ));
    }

    private boolean isUnder21(LocalDate dateOfBirth) {
        return Period.between(dateOfBirth, LocalDate.now()).getYears() < 21;
    }

    private MemberResponse toResponse(Member m) {
        return new MemberResponse(
                m.getId(),
                m.getFirstName(),
                m.getLastName(),
                m.getEmail(),
                m.getDateOfBirth(),
                m.getMembershipDate(),
                m.getMembershipNumber(),
                m.getStatus(),
                m.isUnder21(),
                false // preventionOfficer flag comes from StaffAccount, not Member
        );
    }
}
