/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License;
 * you may not use this file except in compliance with the Elastic License.
 */
package org.elasticsearch.xpack.core.action;

import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ActionType;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.support.master.MasterNodeRequest;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.util.CollectionUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

import static org.elasticsearch.action.ValidateActions.addValidationError;

public class DeleteDataStreamAction extends ActionType<AcknowledgedResponse> {

    public static final DeleteDataStreamAction INSTANCE = new DeleteDataStreamAction();
    public static final String NAME = "indices:admin/data_stream/delete";

    private DeleteDataStreamAction() {
        super(NAME, AcknowledgedResponse::new);
    }

    public static class Request extends MasterNodeRequest<Request> implements IndicesRequest.Replaceable {

        private String[] names;

        // Security intercepts requests and rewrites names if wildcards are used to expand to concrete resources
        // that a user has privileges for.
        // This keeps track whether wildcards were originally specified in names,
        // So that in the case no matches ds are found, that either an
        // empty response can be returned in case wildcards were used or
        // 404 status code returned in case no wildcard were used.
        private final boolean wildcardExpressionsOriginallySpecified;

        public Request(String[] names) {
            this.names = Objects.requireNonNull(names);
            this.wildcardExpressionsOriginallySpecified = Arrays.stream(names).anyMatch(Regex::isSimpleMatchPattern);
        }

        public String[] getNames() {
            return names;
        }

        @Override
        public ActionRequestValidationException validate() {
            ActionRequestValidationException validationException = null;
            if (CollectionUtils.isEmpty(names)) {
                validationException = addValidationError("no data stream(s) specified", validationException);
            }
            return validationException;
        }

        public Request(StreamInput in) throws IOException {
            super(in);
            this.names = in.readStringArray();
            this.wildcardExpressionsOriginallySpecified = in.getVersion().onOrAfter(Version.V_8_0_0) && in.readBoolean();
        }

        @Override
        public void writeTo(StreamOutput out) throws IOException {
            super.writeTo(out);
            out.writeStringArray(names);
            if (out.getVersion().onOrAfter(Version.V_8_0_0)) {
                out.writeBoolean(wildcardExpressionsOriginallySpecified);
            }
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Request request = (Request) o;
            return wildcardExpressionsOriginallySpecified == request.wildcardExpressionsOriginallySpecified &&
                Arrays.equals(names, request.names);
        }

        @Override
        public int hashCode() {
            int result = Objects.hash(wildcardExpressionsOriginallySpecified);
            result = 31 * result + Arrays.hashCode(names);
            return result;
        }

        @Override
        public String[] indices() {
            return names;
        }

        @Override
        public IndicesOptions indicesOptions() {
            // this doesn't really matter since data stream name resolution isn't affected by IndicesOptions and
            // a data stream's backing indices are retrieved from its metadata
            return IndicesOptions.fromOptions(false, true, true, true, false, false, true, false);
        }

        @Override
        public boolean includeDataStreams() {
            return true;
        }

        @Override
        public IndicesRequest indices(String... indices) {
            this.names = indices;
            return this;
        }

        public boolean isWildcardExpressionsOriginallySpecified() {
            return wildcardExpressionsOriginallySpecified;
        }
    }

}

@@ -2926,26 +2926,27 @@
 r(Version.V_
-8_
+7_1
 0_0) && in.r
@@ -3185,10 +3185,11 @@
 n.V_
-8_
+7_1
 0_0)

Fix Broken DeleteDataStreamAction BwC Serialization (#62286)