package de.avatic.lcc.service.apps;

import de.avatic.lcc.dto.configuration.apps.AppDTO;
import de.avatic.lcc.model.db.users.App;
import de.avatic.lcc.repositories.users.AppRepository;
import de.avatic.lcc.service.transformer.apps.AppTransformer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
public class AppsService {

    private final AppRepository appRepository;
    private final AppTransformer appTransformer;
    private final PasswordEncoder passwordEncoder;

    public AppsService(AppRepository appRepository, AppTransformer appTransformer, PasswordEncoder passwordEncoder) {
        this.appRepository = appRepository;
        this.appTransformer = appTransformer;
        this.passwordEncoder = passwordEncoder;
    }

    public List<AppDTO> listApps() {
        return appRepository.listApps().stream().map(appTransformer::toAppDTO).toList();
    }

    public AppDTO updateApp(AppDTO dto) {

        var newApp = dto.getId() == null;
        String appSecret = null;

        if(newApp) {
            dto.setClientId(generateAppId());
            appSecret = generateAppSecret();
            dto.setClientSecret(passwordEncoder.encode(appSecret));
        }

        var id = appRepository.update(appTransformer.toAppEntity(dto));

        if(newApp) {
            dto.setId(id);
            dto.setClientSecret(appSecret);
        }

        return dto;
    }

    private String generateAppId() {
        return UUID.randomUUID().toString();
    }

    private String generateAppSecret() {
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[32];
        random.nextBytes(bytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }

    public void deleteApp(Integer id) {
        appRepository.delete(id);
    }


    public Optional<App> validateApp(String clientId, String clientSecret) {
        var app = appRepository.getByClientId(clientId);

        if (app.isPresent() &&
                passwordEncoder.matches(clientSecret, app.get().getClientSecret())) {
            return app;
        }

        return Optional.empty();

    }

}
