package study.iot.command.support;

import com.hivemq.extension.sdk.api.ExtensionMain;
import com.hivemq.extension.sdk.api.annotations.NotNull;
import com.hivemq.extension.sdk.api.auth.SimpleAuthenticator;
import com.hivemq.extension.sdk.api.auth.parameter.TopicPermission;
import com.hivemq.extension.sdk.api.packets.auth.ModifiableDefaultPermissions;
import com.hivemq.extension.sdk.api.packets.connect.ConnackReasonCode;
import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput;
import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput;
import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput;
import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput;
import com.hivemq.extension.sdk.api.services.Services;
import com.hivemq.extension.sdk.api.services.builder.Builders;

import java.nio.charset.StandardCharsets;

/**
 * 与 U88 相同的设备身份与 ACL 教学扩展：device-&lt;id&gt;/secret-&lt;id&gt; 凭证，
 * 普通设备只能操作 devices/&lt;id&gt;/#，svc- 前缀的服务账号可以操作 devices/#。
 * 本模块独立一份，避免实验之间耦合。
 */
public final class DeviceSecurityMain implements ExtensionMain {

    public static final String DEVICE_PREFIX = "device-";
    public static final String SECRET_PREFIX = "secret-";
    public static final String SERVICE_PREFIX = "svc-";

    @Override
    public void extensionStart(@NotNull ExtensionStartInput input, @NotNull ExtensionStartOutput output) {
        Services.securityRegistry().setAuthenticatorProvider(providerInput -> {
            String clientId = providerInput.getClientInformation().getClientId();
            return (SimpleAuthenticator) (authInput, authOutput) -> {
                var connect = authInput.getConnectPacket();
                String user = connect.getUserName().map(Object::toString).orElse("");
                String password = connect.getPassword()
                        .map(buffer -> {
                            byte[] bytes = new byte[buffer.remaining()];
                            buffer.duplicate().get(bytes);
                            return new String(bytes, StandardCharsets.UTF_8);
                        })
                        .orElse("");
                if (!(DEVICE_PREFIX + clientId).equals(user) || !(SECRET_PREFIX + clientId).equals(password)) {
                    authOutput.failAuthentication(ConnackReasonCode.NOT_AUTHORIZED, "device credentials rejected");
                    return;
                }
                String topicFilter = clientId.startsWith(SERVICE_PREFIX)
                        ? "devices/#"
                        : "devices/" + clientId + "/#";
                ModifiableDefaultPermissions permissions = authOutput.getDefaultPermissions();
                permissions.add(Builders.topicPermission()
                        .topicFilter(topicFilter)
                        .type(TopicPermission.PermissionType.ALLOW)
                        .qos(TopicPermission.Qos.ALL)
                        .activity(TopicPermission.MqttActivity.ALL)
                        .retain(TopicPermission.Retain.ALL)
                        .sharedSubscription(TopicPermission.SharedSubscription.ALL)
                        .sharedGroup("#")
                        .build());
                authOutput.authenticateSuccessfully();
            };
        });
    }

    @Override
    public void extensionStop(@NotNull ExtensionStopInput input, @NotNull ExtensionStopOutput output) {
        // 无需清理。
    }
}
