/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you 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.wso2.carbon.apimgt.application.extension;

import feign.FeignException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.application.extension.constants.ApiApplicationConstants;
import org.wso2.carbon.apimgt.application.extension.dto.ApiApplicationKey;
import org.wso2.carbon.apimgt.application.extension.exception.APIManagerException;
import org.wso2.carbon.apimgt.application.extension.internal.APIApplicationManagerExtensionDataHolder;
import org.wso2.carbon.apimgt.application.extension.util.APIManagerUtil;
import org.wso2.carbon.apimgt.integration.client.store.*;
import org.wso2.carbon.apimgt.integration.generated.client.store.model.*;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This class represents an implementation of APIManagementProviderService.
 */
public class APIManagementProviderServiceImpl implements APIManagementProviderService {

    private static final Log log = LogFactory.getLog(APIManagementProviderServiceImpl.class);
    private static final String CONTENT_TYPE = "application/json";
    private static final int MAX_API_PER_TAG = 200;
    private static final String APP_TIER_TYPE = "application";

    public boolean isTierLoaded() {
        StoreClient storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
                .getStoreClient();
        String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext()
                .getTenantDomain();
        try {

            storeClient.getIndividualTier().tiersTierLevelTierNameGet(ApiApplicationConstants.DEFAULT_TIER,
                                                                      APP_TIER_TYPE,
                                                                      tenantDomain, CONTENT_TYPE, null, null);
            return true;
        } catch (FeignException e) {
            return false;
        }
    }

    @Override
    public void removeAPIApplication(String applicationName, String username) throws APIManagerException {

        StoreClient storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
                .getStoreClient();
        ApplicationList applicationList = storeClient.getApplications()
                .applicationsGet("", applicationName, 1, 0, CONTENT_TYPE, null);
        if (applicationList.getList() != null && applicationList.getList().size() > 0) {
            ApplicationInfo applicationInfo = applicationList.getList().get(0);
            storeClient.getIndividualApplication().applicationsApplicationIdDelete(applicationInfo.getApplicationId(),
                                                                                   null, null);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized ApiApplicationKey generateAndRetrieveApplicationKeys(String applicationName, String tags[],
                                                                String keyType, String username,
                                                                boolean isAllowedAllDomains, String validityTime)
            throws APIManagerException {
        StoreClient storeClient = APIApplicationManagerExtensionDataHolder.getInstance().getIntegrationClientService()
                .getStoreClient();
        String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext()
                .getTenantDomain();

        ApplicationList applicationList = storeClient.getApplications()
                .applicationsGet("", applicationName, 1, 0, CONTENT_TYPE, null);
        Application application;
        if (applicationList == null || applicationList.getList() == null || applicationList.getList().size() == 0) {
            //create application;
            application = new Application();
            application.setName(applicationName);
            application.setSubscriber(username);
            application.setDescription("");
            application.setThrottlingTier(ApiApplicationConstants.DEFAULT_TIER);
            application.setGroupId("");
            application = storeClient.getIndividualApplication().applicationsPost(application, CONTENT_TYPE);
        } else {
            ApplicationInfo applicationInfo = applicationList.getList().get(0);
            application = storeClient.getIndividualApplication()
                    .applicationsApplicationIdGet(applicationInfo.getApplicationId(), CONTENT_TYPE, null, null);
        }
        if (application == null) {
            throw new APIManagerException (
                    "Api application creation failed for " + applicationName + " to the user " + username);
        }

        SubscriptionList subscriptionList = storeClient.getSubscriptions().subscriptionsGet
                (null, application.getApplicationId(), "", 0, 100, CONTENT_TYPE, null);
        List<Subscription> needToSubscribe = new ArrayList<>();
        // subscribe to apis.
        if (tags != null && tags.length > 0) {
            for (String tag: tags) {
                APIList apiList = storeClient.getApis().apisGet(MAX_API_PER_TAG, 0, tenantDomain, "tag:" + tag
                        , CONTENT_TYPE, null);
                if (apiList.getList() == null || apiList.getList().size() == 0) {
                    apiList = storeClient.getApis().apisGet(MAX_API_PER_TAG, 0
                            , MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, "tag:" + tag, CONTENT_TYPE, null);
                }

                if (apiList.getList() != null && apiList.getList().size() > 0) {
                    for (APIInfo apiInfo : apiList.getList()) {
                        String id = apiInfo.getProvider().replace("@", "-AT-")
                                + "-" + apiInfo.getName()+ "-" + apiInfo.getVersion();
                        boolean subscriptionExist = false;
                        if (subscriptionList.getList() != null && subscriptionList.getList().size() > 0) {
                            for (Subscription subs : subscriptionList.getList()) {
                                if (subs.getApiIdentifier().equals(id)) {
                                    subscriptionExist = true;
                                    break;
                                }
                            }
                        }
                        if (!subscriptionExist) {
                            Subscription subscription = new Subscription();
                            //fix for APIMANAGER-5566 admin-AT-tenant1.com-Tenant1API1-1.0.0

                            subscription.setApiIdentifier(id);
                            subscription.setApplicationId(application.getApplicationId());
                            subscription.tier(ApiApplicationConstants.DEFAULT_TIER);
                            if (!needToSubscribe.contains(subscription)){
                                needToSubscribe.add(subscription);
                            }
                        }
                    }
                }
            }
        }
        if (!needToSubscribe.isEmpty()) {
            storeClient.getSubscriptionMultitpleApi().subscriptionsMultiplePost(needToSubscribe, CONTENT_TYPE);
        }
        //end of subscription

        List<ApplicationKey> applicationKeys = application.getKeys();
        if (applicationKeys != null) {
            for (ApplicationKey applicationKey : applicationKeys) {
                if (keyType.equals(applicationKey.getKeyType().toString())) {
                    ApiApplicationKey apiApplicationKey = new ApiApplicationKey();
                    apiApplicationKey.setConsumerKey(applicationKey.getConsumerKey());
                    apiApplicationKey.setConsumerSecret(applicationKey.getConsumerSecret());
                    return apiApplicationKey;
                }
            }
        }

        ApplicationKeyGenerateRequest applicationKeyGenerateRequest = new ApplicationKeyGenerateRequest();
        List<String> allowedDomains = new ArrayList<>();
        if (isAllowedAllDomains) {
            allowedDomains.add(ApiApplicationConstants.ALLOWED_DOMAINS);
        } else {
            allowedDomains.add(APIManagerUtil.getTenantDomain());
        }
        applicationKeyGenerateRequest.setAccessAllowDomains(allowedDomains);
        applicationKeyGenerateRequest.setCallbackUrl("");
        applicationKeyGenerateRequest.setKeyType(ApplicationKeyGenerateRequest.KeyTypeEnum.PRODUCTION);
        applicationKeyGenerateRequest.setValidityTime(validityTime);

        ApplicationKey applicationKey = storeClient.getIndividualApplication().applicationsGenerateKeysPost(
                application.getApplicationId(), applicationKeyGenerateRequest, CONTENT_TYPE, null, null);
        ApiApplicationKey apiApplicationKey = new ApiApplicationKey();
        apiApplicationKey.setConsumerKey(applicationKey.getConsumerKey());
        apiApplicationKey.setConsumerSecret(applicationKey.getConsumerSecret());
        return apiApplicationKey;
    }

}
