package es.tatvil.taiageweb.servicio;

import es.tatvil.taiageweb.modelo.Usuario;
import es.tatvil.taiageweb.repositorio.UsuarioRepository;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UsuarioService implements UserDetailsService {

    private final UsuarioRepository repo;
    private final PasswordEncoder encoder;

    public UsuarioService(UsuarioRepository repo, PasswordEncoder encoder) {
        this.repo = repo;
        this.encoder = encoder;
    }

    // ── Spring Security ──────────────────────────────────────

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        Usuario u = repo.findByEmail(email)
                .orElseThrow(() -> new UsernameNotFoundException("Usuario no encontrado: " + email));

        var authorities = u.getRoles().stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());

        return new org.springframework.security.core.userdetails.User(
                u.getEmail(), u.getPassword(),
                u.isHabilitado(),   // enabled
                true,               // accountNonExpired
                true,               // credentialsNonExpired
                true,               // accountNonLocked
                authorities
        );
    }

    // ── Auto-registro (pendiente de activación) ──────────────

    @Transactional
    public void registrar(String email, String passwordPlana) {
        if (repo.existsByEmail(email)) {
            throw new IllegalArgumentException("El email ya está registrado");
        }
        if (passwordPlana.length() < 8) {
            throw new IllegalArgumentException("La contraseña debe tener al menos 8 caracteres");
        }
        Usuario u = new Usuario();
        u.setEmail(email);
        u.setPassword(encoder.encode(passwordPlana));
        u.setHabilitado(false);           // pendiente de activación por admin
        u.setRoles(new HashSet<>(Set.of("ROLE_USER")));
        repo.save(u);
    }

    // ── Consultas ────────────────────────────────────────────

    public List<Usuario> listarTodos() {
        return repo.findAll();
    }

    // ── Acciones de admin ────────────────────────────────────

    @Transactional
    public void toggleHabilitado(Long id) {
        Usuario u = repo.findById(id).orElseThrow();
        u.setHabilitado(!u.isHabilitado());
    }

    @Transactional
    public void toggleRolPagado(Long id) {
        Usuario u = repo.findById(id).orElseThrow();
        if (u.getRoles().contains("ROLE_PAGADO")) {
            u.getRoles().remove("ROLE_PAGADO");
        } else {
            u.getRoles().add("ROLE_PAGADO");
        }
    }

    /** Concede acceso al curso tras un pago confirmado por Stripe (nunca quita el rol) */
    @Transactional
    public void darAccesoPagado(Long id) {
        Usuario u = repo.findById(id).orElseThrow();
        u.getRoles().add("ROLE_PAGADO");
        u.setHabilitado(true);
    }

    /** El admin crea directamente un usuario ya activo */
    @Transactional
    public void crearPorAdmin(String email, String passwordPlana, boolean pagado) {
        if (repo.existsByEmail(email)) {
            throw new IllegalArgumentException("El email ya está registrado");
        }
        Usuario u = new Usuario();
        u.setEmail(email);
        u.setPassword(encoder.encode(passwordPlana));
        u.setHabilitado(true);
        Set<String> roles = new HashSet<>();
        roles.add("ROLE_USER");
        if (pagado) roles.add("ROLE_PAGADO");
        u.setRoles(roles);
        repo.save(u);
    }

    @Transactional
    public void eliminar(Long id) {
        repo.deleteById(id);
    }
}
