package api

import (
	"net/http"

	"code.justin.tv/d8a/buddy/lib/clusters"
	"code.justin.tv/d8a/buddy/lib/config"

	"fmt"

	"code.justin.tv/d8a/buddy/lib/clusters/clusterdb"
	"golang.org/x/net/context"
)

// PairStatus checks on role pairs for each cluster & verifies that they're health:
// - One active & one inactive user
// - Sandstorm credentials for active user work
// - Any services are hooked up to the active user credentials
func (s *Server) PairStatus(c context.Context, w http.ResponseWriter, r *http.Request) {
	err := clusters.ProcessInParallel(s.config.Cluster, func(cluster *config.Cluster) (interface{}, error) {
		db, err := clusterdb.OpenDbConn(cluster, s.sandstormClient, cluster.SuperUser)
		if err != nil {
			return nil, fmt.Errorf("could not open a connection to cluster %s", cluster.Name)
		}

		users, err := db.ClusterUsers()
		if err != nil {
			return nil, fmt.Errorf("could not retrieve users from cluster %s", cluster.Name)
		}

		for _, role := range cluster.RolePair {
			//Verify that the role has two users: one active & one inactive
			if len(role.Users) != 2 {
				return nil, fmt.Errorf("role %s had %d linked users, instead of the expected 2", role.Name, len(role.Users))
			}

			var foundOnUser, foundOffUser bool
			var onUser string
			for _, user := range role.Users {
				isOn := users[user.Name]
				if isOn && !foundOnUser {
					foundOnUser = true
					onUser = user.Name
				} else if !isOn && !foundOffUser {
					foundOffUser = true
				} else if isOn {
					return nil, fmt.Errorf("both users in the role %s were marked as LOGIN", role.Name)
				} else {
					return nil, fmt.Errorf("both users in the role %s were marked as NOLOGIN", role.Name)
				}
			}

			//Verify that user credentials for active user work
			oldPassword, err := s.sandstormClient.GetUserPassword(cluster, onUser)
			if err != nil {
				return nil, fmt.Errorf("could not retrieve password for user %s in role %s from sandstorm", onUser, role.Name)
			}

			_, err = clusterdb.OpenDbConnWithManualSecret(cluster, onUser, oldPassword)
			if err != nil {
				return nil, fmt.Errorf("cannot log into active user %s in role %s", onUser, role.Name)
			}

			//Verify credentials for each service match
			for _, service := range role.RoleServices {
				userValue, err := s.sandstormClient.Manager().Get(service.UsernameSecret)
				if err != nil {
					return nil, fmt.Errorf("could not retrieve '%s' from sandstorm for service %s in role %s", service.UsernameSecret, service.Name, role.Name)
				}
				passwordValue, err := s.sandstormClient.Manager().Get(service.PasswordSecret)
				if err != nil {
					return nil, fmt.Errorf("could not retrieve '%s' from sandstorm for service %s in role %s", service.PasswordSecret, service.Name, role.Name)
				}

				if string(userValue.Plaintext) != onUser || string(passwordValue.Plaintext) != oldPassword {
					return nil, fmt.Errorf("the credentials for service %s of role %s do not match the ones in use by the database user", service.Name, role.Name)
				}
			}
		}

		return nil, nil
	}, func(result interface{}, err error) error {
		return err
	})

	if err != nil {
		writeText(w, fmt.Sprintf("%v", err))
	} else {
		writeText(w, "OK")
	}
}
