package com.cameleer.server.core.runtime;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;

public class EnvironmentService {

    /**
     * Slug must start with a lowercase letter or digit, contain only lowercase
     * letters, digits, and hyphens, and be 1–64 characters long. Slugs are
     * immutable after creation — they appear in URLs, Docker network names,
     * container names, and ClickHouse partition keys, so renaming is not
     * supported by design.
     */
    private static final Pattern SLUG_PATTERN = Pattern.compile("^[a-z0-9][a-z0-9-]{0,63}$");

    private final EnvironmentRepository repo;
    private final CreateGuard createGuard;

    public EnvironmentService(EnvironmentRepository repo) {
        this(repo, CreateGuard.NOOP);
    }

    public EnvironmentService(EnvironmentRepository repo, CreateGuard createGuard) {
        this.repo = repo;
        this.createGuard = createGuard;
    }

    public List<Environment> listAll() { return repo.findAll(); }

    public Environment getById(UUID id) {
        return repo.findById(id).orElseThrow(() -> new IllegalArgumentException("Environment not found: " + id));
    }

    public Environment getBySlug(String slug) {
        return repo.findBySlug(slug).orElseThrow(() -> new IllegalArgumentException("Environment not found: " + slug));
    }

    public UUID create(String slug, String displayName, boolean production) {
        if (slug == null || !SLUG_PATTERN.matcher(slug).matches()) {
            throw new IllegalArgumentException(
                    "Invalid slug: must match ^[a-z0-9][a-z0-9-]{0,63}$ (lowercase letters, digits, hyphens)");
        }
        createGuard.check(repo.count());
        if (repo.findBySlug(slug).isPresent()) {
            throw new IllegalArgumentException("Environment with slug '" + slug + "' already exists");
        }
        return repo.create(slug, displayName, production);
    }

    /**
     * Update mutable environment fields. Color is validated against
     * {@link EnvironmentColor#VALUES}. Unknown colors raise
     * {@link IllegalArgumentException}; the controller maps that to 400.
     */
    public void update(UUID id, String displayName, boolean production, boolean enabled, String color) {
        getById(id); // verify exists
        if (!EnvironmentColor.isValid(color)) {
            throw new IllegalArgumentException("unknown environment color: " + color);
        }
        repo.update(id, displayName, production, enabled, color);
    }

    public void updateDefaultContainerConfig(UUID id, Map<String, Object> defaultContainerConfig) {
        getById(id); // verify exists
        repo.updateDefaultContainerConfig(id, defaultContainerConfig);
    }

    public void updateJarRetentionCount(UUID id, Integer jarRetentionCount) {
        getById(id); // verify exists
        if (jarRetentionCount != null && jarRetentionCount < 1) {
            throw new IllegalArgumentException("Retention count must be at least 1 or null for unlimited");
        }
        repo.updateJarRetentionCount(id, jarRetentionCount);
    }

    public void delete(UUID id) {
        Environment env = getById(id);
        if ("default".equals(env.slug())) {
            throw new IllegalArgumentException("Cannot delete the default environment");
        }
        repo.delete(id);
    }
}
