package study.configbus;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@SpringBootConfiguration
@EnableAutoConfiguration
@Import({LabSecurity.class, ClientApp.State.class})
public class ClientApp {
    @Bean
    @RefreshScope
    Policy policy(@Value("${lab.message:missing}") String message,
                  @Value("${lab.revision:missing}") String revision,
                  @Value("${lab.workers:1}") int workers) {
        return new Policy(message, revision, workers);
    }

    /** A normal singleton captures its value at construction and is not refreshed. */
    @Bean
    Sticky sticky(@Value("${lab.message:missing}") String message) { return new Sticky(message); }

    public record Sticky(String message) { }

    // Non-final: RefreshScope's default TARGET_CLASS proxy must be able to subclass it.
    public static class Policy {
        private final String message;
        private final String revision;
        private final int workers;
        public Policy(String message, String revision, int workers) {
            if (workers < 1 || workers > 64) throw new IllegalArgumentException("workers must be 1..64");
            this.message = message;
            this.revision = revision;
            this.workers = workers;
        }
        public String message() { return message; }
        public String revision() { return revision; }
        public int workers() { return workers; }
    }

    @RestController
    static class State {
        private final Policy policy;
        private final Sticky sticky;
        private final Environment environment;
        State(Policy policy, Sticky sticky, Environment environment) {
            this.policy = policy;
            this.sticky = sticky;
            this.environment = environment;
        }
        @GetMapping("/state")
        Map<String, Object> state() {
            // No raw secret or credentials in the response/log/evidence.
            return Map.of("message", policy.message(), "revision", policy.revision(),
                    "workers", policy.workers(), "sticky", sticky.message(),
                    "environment", environment.getProperty("lab.message", "missing"),
                    "configVersion", environment.getProperty("config.client.version", "missing"),
                    "secretPresent", environment.containsProperty("lab.secret"));
        }
    }
}
