package net.siegeln.cameleer.saas.onboarding;

import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
import net.siegeln.cameleer.saas.tenant.TenantEntity;
import net.siegeln.cameleer.saas.tenant.dto.CreateTenantRequest;
import net.siegeln.cameleer.saas.vendor.VendorTenantService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.UUID;

/**
 * Self-service onboarding: lets a newly registered user create their own trial tenant.
 * Reuses VendorTenantService for the heavy lifting (Logto org, license, Docker provisioning)
 * but adds the calling user as the tenant owner instead of creating a new admin user.
 */
@Service
public class OnboardingService {

    private static final Logger log = LoggerFactory.getLogger(OnboardingService.class);

    private final VendorTenantService vendorTenantService;
    private final LogtoManagementClient logtoClient;

    public OnboardingService(VendorTenantService vendorTenantService,
                             LogtoManagementClient logtoClient) {
        this.vendorTenantService = vendorTenantService;
        this.logtoClient = logtoClient;
    }

    public TenantEntity createTrialTenant(String name, String slug, String logtoUserId) {
        // Guard: check if user already has a tenant (prevent abuse)
        if (logtoClient.isAvailable()) {
            var orgs = logtoClient.getUserOrganizations(logtoUserId);
            if (!orgs.isEmpty()) {
                throw new IllegalStateException("You already have a tenant. Only one trial tenant per account.");
            }
        }

        // Create tenant via the existing vendor flow (no admin user — we'll add the caller)
        UUID actorId = resolveActorId(logtoUserId);
        var request = new CreateTenantRequest(name, slug, "LOW", null, null);
        TenantEntity tenant = vendorTenantService.createAndProvision(request, actorId);

        // Add the calling user to the Logto org as owner
        if (tenant.getLogtoOrgId() != null && logtoClient.isAvailable()) {
            try {
                String ownerRoleId = logtoClient.findOrgRoleIdByName("owner");
                logtoClient.addUserToOrganization(tenant.getLogtoOrgId(), logtoUserId);
                if (ownerRoleId != null) {
                    logtoClient.assignOrganizationRole(tenant.getLogtoOrgId(), logtoUserId, ownerRoleId);
                }
                log.info("Added user {} as owner of tenant {}", logtoUserId, slug);

                // Set display name from email if not already set (email-registered users have no name)
                var user = logtoClient.getUser(logtoUserId);
                if (user != null && (user.get("name") == null || String.valueOf(user.get("name")).isBlank())) {
                    String email = String.valueOf(user.getOrDefault("primaryEmail", ""));
                    if (!email.isBlank() && email.contains("@")) {
                        String displayName = email.substring(0, email.indexOf('@'));
                        logtoClient.updateUserProfile(logtoUserId, Map.of("name", displayName));
                        log.info("Set display name '{}' for user {}", displayName, logtoUserId);
                    }
                }
            } catch (Exception e) {
                log.warn("Failed to add user {} to org for tenant {}: {}", logtoUserId, slug, e.getMessage());
            }
        }

        return tenant;
    }

    private UUID resolveActorId(String subject) {
        try {
            return UUID.fromString(subject);
        } catch (IllegalArgumentException e) {
            return UUID.nameUUIDFromBytes(subject.getBytes());
        }
    }
}
