/*
 * Copyright 2016 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.keycloak.testsuite.util.cli;

import java.util.HashSet;
import java.util.Set;

import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils;

/**
 * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
 */
public class RoleCommands {

    public static class CreateRoles extends AbstractCommand {

        private String rolePrefix;
        private String roleContainer;

        @Override
        public String getName() {
            return "createRoles";
        }

        private class StateHolder {
            int firstInThisBatch;
            int countInThisBatch;
            int remaining;
        };

        @Override
        protected void doRunCommand(KeycloakSession session) {
            rolePrefix = getArg(0);
            roleContainer = getArg(1);
            int first = getIntArg(2);
            int count = getIntArg(3);
            int batchCount = getIntArg(4);

            final StateHolder state = new StateHolder();
            state.firstInThisBatch = first;
            state.remaining = count;
            state.countInThisBatch = Math.min(batchCount, state.remaining);
            while (state.remaining > 0) {
                KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {

                    @Override
                    public void run(KeycloakSession session) {
                        createRolesInBatch(session, roleContainer, rolePrefix, state.firstInThisBatch, state.countInThisBatch);
                    }
                });

                // update state
                state.firstInThisBatch = state.firstInThisBatch + state.countInThisBatch;
                state.remaining = state.remaining - state.countInThisBatch;
                state.countInThisBatch = Math.min(batchCount, state.remaining);
            }

            log.infof("Command finished. All roles from %s to %s created", rolePrefix + first, rolePrefix + (first + count - 1));
        }

        private void createRolesInBatch(KeycloakSession session, String roleContainer, String rolePrefix, int first, int count) {
            RoleContainerModel container = getRoleContainer(session, roleContainer);

            int last = first + count;
            for (int counter = first; counter < last; counter++) {
                String roleName = rolePrefix + counter;
                RoleModel role = container.addRole(roleName);
            }
            log.infof("Roles from %s to %s created", rolePrefix + first, rolePrefix + (last - 1));
        }

        private RoleContainerModel getRoleContainer(KeycloakSession session, String roleContainer) {
            String[] parts = roleContainer.split("/");
            String realmName = parts[0];

            RealmModel realm = session.realms().getRealmByName(realmName);
            if (realm == null) {
                log.errorf("Unknown realm: %s", realmName);
                throw new HandledException();
            }

            if (parts.length == 1) {
                return realm;
            } else {
                String clientId = parts[1];
                ClientModel client = session.realms().getClientByClientId(clientId, realm);
                if (client == null) {
                    log.errorf("Unknown client: %s", clientId);
                    throw new HandledException();
                }

                return client;
            }
        }

        @Override
        public String printUsage() {
            return super.printUsage() + " <role-prefix> <role-container> <starting-role-offset> <total-count> <batch-size> . " +
                    "\n'total-count' refers to total count of newly created roles. 'batch-size' refers to number of created roles in each transaction. 'starting-role-offset' refers to starting role offset." +
                    "\nFor example if 'starting-role-offset' is 15 and total-count is 10 and role-prefix is 'test', it will create roles test15, test16, test17, ... , test24" +
                    "\n'role-container' is either realm (then use just realmName like 'demo' or client (then use realm/clientId like 'demo/my-client' .\n" +
                    "Example usage: " + super.printUsage() + " test demo 0 500 100";
        }

    }
}
