package de.effigenix.infrastructure;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.effigenix.domain.usermanagement.RoleName;
import de.effigenix.domain.usermanagement.UserStatus;
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Set;
import java.util.UUID;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Transactional
public abstract class AbstractIntegrationTest {

    protected static final String BCRYPT_PASS123 = "$2a$10$4tNfKjz7w.67G72CVop9CuuzBh5vrkYJki8lZ66ZwwLtQjlrm6hHy";
    protected static final String TEST_PASSWORD = "Pass123";

    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    protected ObjectMapper objectMapper;

    @Autowired
    protected UserJpaRepository userRepository;

    @Autowired
    protected RoleJpaRepository roleRepository;

    @Value("${jwt.secret}")
    protected String jwtSecret;

    @Value("${jwt.expiration}")
    protected long jwtExpiration;

    protected String generateToken(String userId, String username, String permissions) {
        long now = System.currentTimeMillis();
        SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
                jwtSecret.getBytes(StandardCharsets.UTF_8));
        return Jwts.builder()
                .subject(userId)
                .claim("username", username)
                .claim("permissions", permissions)
                .issuedAt(new Date(now))
                .expiration(new Date(now + jwtExpiration))
                .signWith(key)
                .compact();
    }

    protected String generateExpiredToken(String userId, String username) {
        long now = System.currentTimeMillis();
        SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
                jwtSecret.getBytes(StandardCharsets.UTF_8));
        return Jwts.builder()
                .subject(userId)
                .claim("username", username)
                .claim("permissions", "")
                .issuedAt(new Date(now - 10000))
                .expiration(new Date(now - 5000))
                .signWith(key)
                .compact();
    }

    protected String generateRefreshToken(String userId, String username) {
        long now = System.currentTimeMillis();
        SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
                jwtSecret.getBytes(StandardCharsets.UTF_8));
        return Jwts.builder()
                .subject(userId)
                .claim("username", username)
                .claim("type", "refresh")
                .issuedAt(new Date(now))
                .expiration(new Date(now + 7200000))
                .signWith(key)
                .compact();
    }

    protected RoleEntity createRole(RoleName roleName, String description) {
        RoleEntity role = new RoleEntity(
                UUID.randomUUID().toString(), roleName, Set.of(), description);
        return roleRepository.save(role);
    }

    protected UserEntity createUser(String username, String email, Set<RoleEntity> roles, String branchId) {
        UserEntity user = new UserEntity(
                UUID.randomUUID().toString(), username, email,
                BCRYPT_PASS123, roles,
                branchId, UserStatus.ACTIVE, OffsetDateTime.now(ZoneOffset.UTC), null);
        return userRepository.save(user);
    }
}
