// Copyright 2017 Google Inc.
//
// 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 apidApigeeSync

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/apid/apid-core"
	"github.com/apid/apid-core/util"
)

const (
	configPollInterval        = "apigeesync_poll_interval"
	configProxyServerBaseURI  = "apigeesync_proxy_server_base"
	configSnapServerBaseURI   = "apigeesync_snapshot_server_base"
	configChangeServerBaseURI = "apigeesync_change_server_base"
	configConsumerKey         = "apigeesync_consumer_key"
	configConsumerSecret      = "apigeesync_consumer_secret"
	configApidClusterId       = "apigeesync_cluster_id"
	configSnapshotProtocol    = "apigeesync_snapshot_proto"
	configName                = "apigeesync_instance_name"
	configDiagnosticMode      = "apigeesync_diagnostic_mode"
	// special value - set by ApigeeSync, not taken from configuration
	configApidInstanceID = "apigeesync_apid_instance_id"
	// This will not be needed once we have plugin handling tokens.
	configBearerToken      = "apigeesync_bearer_token"
	configLocalStoragePath = "local_storage_path"
)

const (
	ApigeeSyncEventSelector = "ApigeeSync"
)

var (
	/* All set during plugin initialization */
	log          apid.LogService
	config       apid.ConfigService
	dataService  apid.DataService
	eventService apid.EventsService
	apiService   apid.APIService
	apidInfo     apidInstanceInfo

	/* Set during post plugin initialization
	 * set this as a default, so that it's guaranteed to be valid even if postInitPlugins isn't called
	 */
	apidPluginDetails string = `[{"name":"apidApigeeSync","schemaVer":"1.0"}]`
)

type apidInstanceInfo struct {
	InstanceID, InstanceName, ClusterID, LastSnapshot string
	IsNewInstance                                     bool
}

type pluginDetail struct {
	Name          string `json:"name"`
	SchemaVersion string `json:"schemaVer"`
}

func init() {
	apid.RegisterPlugin(initPlugin, PluginData)
}

func initConfigDefaults() {
	config.SetDefault(configPollInterval, 120*time.Second)
	config.SetDefault(configSnapshotProtocol, "sqlite")
	config.SetDefault(configDiagnosticMode, false)

	name, errh := os.Hostname()
	if (errh != nil) && (len(config.GetString(configName)) == 0) {
		log.Errorf("Not able to get hostname for kernel. Please set '%s' property in config", configName)
		name = "Undefined"
	}
	config.SetDefault(configName, name)
	log.Debugf("Using %s as display name", config.GetString(configName))
}

func checkForRequiredValues(isOfflineMode bool) error {
	required := []string{configProxyServerBaseURI, configConsumerKey, configConsumerSecret}
	if !isOfflineMode {
		required = append(required, configSnapServerBaseURI, configChangeServerBaseURI)
	}
	// check for required values
	for _, key := range required {
		if !config.IsSet(key) {
			return fmt.Errorf("missing required config value: %s", key)
		}
	}
	proto := config.GetString(configSnapshotProtocol)
	if proto != "sqlite" {
		return fmt.Errorf("illegal value for %s. Only currently supported snashot protocol is sqlite", configSnapshotProtocol)
	}

	return nil
}

func SetLogger(logger apid.LogService) {
	log = logger
}

func initManagers(isOfflineMode bool) (*listenerManager, *ApiManager, error) {
	// check for forward proxy
	var tr *http.Transport
	tr = util.Transport(config.GetString(util.ConfigfwdProxyPortURL))
	tr.MaxIdleConnsPerHost = maxIdleConnsPerHost

	apidDbManager := creatDbManager()
	db, err := dataService.DB()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to access DB: %v", err)
	}
	apidDbManager.setDB(db)
	err = apidDbManager.initDB()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to access DB: %v", err)
	}

	apidInfo, err = apidDbManager.getApidInstanceInfo()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to get apid instance info: %v", err)
	}

	if config.IsSet(configApidInstanceID) {
		log.Warnf("ApigeeSync plugin overriding %s.", configApidInstanceID)
	}
	config.Set(configApidInstanceID, apidInfo.InstanceID)

	apidTokenManager := createApidTokenManager(apidInfo.IsNewInstance)
	var snapMan snapshotManager
	var apidChangeManager changeManager

	if isOfflineMode {
		snapMan = &offlineSnapshotManager{
			dbMan: apidDbManager,
		}
		apidChangeManager = &offlineChangeManager{}
	} else {
		httpClient := &http.Client{
			Transport: tr,
			Timeout:   httpTimeout,
			CheckRedirect: func(req *http.Request, _ []*http.Request) error {
				req.Header.Set("Authorization", "Bearer "+apidTokenManager.getBearerToken())
				return nil
			},
		}
		snapMan = createSnapShotManager(apidDbManager, apidTokenManager, httpClient)
		apidChangeManager = createChangeManager(apidDbManager, snapMan, apidTokenManager, httpClient)
	}

	listenerMan := &listenerManager{
		changeMan:     apidChangeManager,
		snapMan:       snapMan,
		tokenMan:      apidTokenManager,
		isOfflineMode: isOfflineMode,
	}

	apiMan := &ApiManager{
		endpoint: tokenEndpoint,
		tokenMan: apidTokenManager,
	}
	return listenerMan, apiMan, nil
}

func initPlugin(services apid.Services) (apid.PluginData, error) {
	SetLogger(services.Log().ForModule("apigeeSync"))
	dataService = services.Data()
	eventService = services.Events()
	apiService = services.API()
	log.Debug("start init")
	config = services.Config()
	initConfigDefaults()

	isOfflineMode := false
	if config.GetBool(configDiagnosticMode) {
		log.Warn("Diagnostic mode: will not download changelist and snapshots!")
		isOfflineMode = true
	}

	err := checkForRequiredValues(isOfflineMode)
	if err != nil {
		return PluginData, err
	}
	if err != nil {
		return PluginData, err
	}
	listenerMan, apiMan, err := initManagers(isOfflineMode)
	if err != nil {
		return PluginData, err
	}
	listenerMan.init()
	apiMan.InitAPI(apiService)

	log.Debug("end init")
	return PluginData, nil
}
