package de.cannamanage.api.controller;

import de.cannamanage.api.dto.compliance.QuotaResponse;
import de.cannamanage.api.security.JwtService;
import de.cannamanage.domain.entity.Member;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.enums.MemberStatus;
import de.cannamanage.service.repository.MemberRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClient;

import java.time.LocalDate;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
 * Integration tests for {@link ComplianceController}.
 * Boots the full Spring context with H2 in-memory DB.
 * Tests quota status endpoint with JWT authentication.
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class ComplianceControllerIntegrationTest {

    @LocalServerPort
    private int port;

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private JwtService jwtService;

    private RestClient restClient;

    private static final UUID TENANT_ID = UUID.fromString("00000000-0000-0000-0000-000000000001");
    private static final UUID USER_ID = UUID.fromString("00000000-0000-0000-0000-000000000099");

    private UUID memberId;
    private String adminToken;

    @BeforeEach
    void setUp() {
        memberRepository.deleteAll();

        TenantContext.setCurrentTenant(TENANT_ID);

        // Create a test member (adult, 25 years old)
        Member member = new Member();
        member.setClubId(UUID.fromString("00000000-0000-0000-0000-000000000010"));
        member.setFirstName("Max");
        member.setLastName("Mustermann");
        member.setEmail("max@test.club");
        member.setDateOfBirth(LocalDate.now().minusYears(25));
        member.setMembershipDate(LocalDate.now().minusMonths(6));
        member.setMembershipNumber("CM-2025-001");
        member.setStatus(MemberStatus.ACTIVE);
        member.setUnder21(false);
        member = memberRepository.saveAndFlush(member);
        memberId = member.getId();

        TenantContext.clear();

        // Generate a JWT token for authentication
        adminToken = jwtService.generateAccessToken(USER_ID, TENANT_ID, "ADMIN", "admin@test.club");

        restClient = RestClient.builder()
                .baseUrl("http://localhost:" + port)
                .defaultHeader("Authorization", "Bearer " + adminToken)
                .build();
    }

    @Test
    @DisplayName("GET /api/v1/compliance/quota/{memberId} — returns quota for adult member")
    void getQuotaStatus_adultMember_returnsQuota() {
        QuotaResponse response = restClient.get()
                .uri("/api/v1/compliance/quota/{memberId}", memberId)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .body(QuotaResponse.class);

        assertThat(response).isNotNull();
        assertThat(response.totalAllowed()).isEqualByComparingTo("50");
        assertThat(response.totalUsed()).isEqualByComparingTo("0");
        assertThat(response.remaining()).isEqualByComparingTo("50");
        assertThat(response.under21()).isFalse();
        assertThat(response.year()).isEqualTo(LocalDate.now().getYear());
        assertThat(response.month()).isEqualTo(LocalDate.now().getMonthValue());
    }

    @Test
    @DisplayName("GET /api/v1/compliance/quota/{memberId} — under-21 member gets reduced limit")
    void getQuotaStatus_under21Member_returnsReducedLimit() {
        // Create under-21 member
        TenantContext.setCurrentTenant(TENANT_ID);
        Member youngMember = new Member();
        youngMember.setClubId(UUID.fromString("00000000-0000-0000-0000-000000000010"));
        youngMember.setFirstName("Jung");
        youngMember.setLastName("Mitglied");
        youngMember.setEmail("jung@test.club");
        youngMember.setDateOfBirth(LocalDate.now().minusYears(19));
        youngMember.setMembershipDate(LocalDate.now().minusMonths(3));
        youngMember.setMembershipNumber("CM-2025-002");
        youngMember.setStatus(MemberStatus.ACTIVE);
        youngMember.setUnder21(true);
        youngMember = memberRepository.saveAndFlush(youngMember);
        UUID youngMemberId = youngMember.getId();
        TenantContext.clear();

        QuotaResponse response = restClient.get()
                .uri("/api/v1/compliance/quota/{memberId}", youngMemberId)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .body(QuotaResponse.class);

        assertThat(response).isNotNull();
        assertThat(response.totalAllowed()).isEqualByComparingTo("30");
        assertThat(response.under21()).isTrue();
    }

    @Test
    @DisplayName("GET /api/v1/compliance/quota/{memberId} — non-existent member returns 404")
    void getQuotaStatus_nonExistentMember_returns404() {
        UUID nonExistentId = UUID.fromString("00000000-0000-0000-0000-999999999999");

        assertThatThrownBy(() -> restClient.get()
                .uri("/api/v1/compliance/quota/{memberId}", nonExistentId)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .body(String.class))
                .isInstanceOf(HttpClientErrorException.NotFound.class);
    }

    @Test
    @DisplayName("GET /api/v1/compliance/quota/{memberId} — no auth returns 401/403")
    void getQuotaStatus_noAuth_returnsUnauthorized() {
        RestClient unauthClient = RestClient.builder()
                .baseUrl("http://localhost:" + port)
                .build();

        assertThatThrownBy(() -> unauthClient.get()
                .uri("/api/v1/compliance/quota/{memberId}", memberId)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .body(String.class))
                .isInstanceOf(HttpClientErrorException.class)
                .satisfies(ex -> {
                    int status = ((HttpClientErrorException) ex).getStatusCode().value();
                    assertThat(status).isBetween(401, 403);
                });
    }

    @Test
    @DisplayName("GET /api/v1/compliance/quota/{memberId} — invalid token returns 401/403")
    void getQuotaStatus_invalidToken_returnsUnauthorized() {
        RestClient badTokenClient = RestClient.builder()
                .baseUrl("http://localhost:" + port)
                .defaultHeader("Authorization", "Bearer invalid.jwt.token")
                .build();

        assertThatThrownBy(() -> badTokenClient.get()
                .uri("/api/v1/compliance/quota/{memberId}", memberId)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .body(String.class))
                .isInstanceOf(HttpClientErrorException.class)
                .satisfies(ex -> {
                    int status = ((HttpClientErrorException) ex).getStatusCode().value();
                    assertThat(status).isBetween(401, 403);
                });
    }
}
