// Copyright 2021 Google LLC
//
// 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
//
// https://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 operator

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	apiv1 "github.com/google/android-cuttlefish/frontend/src/liboperator/api/v1"
)

// Interface implemented by any connection capable of sending in JSON format
type JSONConn interface {
	Send(val interface{}) error
}

// Log and reply with an error
func ReplyError(c JSONConn, msg string) {
	log.Println(msg)
	if err := c.Send(apiv1.ErrorMsg{Error: msg}); err != nil {
		log.Println("Failed to send error reply: ", err)
	}
}

// Send a JSON http response with success status code to the client
func ReplyJSONOK(w http.ResponseWriter, obj interface{}) error {
	return ReplyJSON(w, obj, http.StatusOK)
}

// Send a JSON http response with error to the client
func ReplyJSONErr(w http.ResponseWriter, err error) error {
	log.Printf("response with error: %v\n", err)
	var e *AppError
	if errors.As(err, &e) {
		return ReplyJSON(w, e.JSONResponse(), e.StatusCode)
	}
	return ReplyJSON(w, apiv1.ErrorMsg{Error: "Internal Server Error"}, http.StatusInternalServerError)
}

// Send a JSON http response to the client
func ReplyJSON(w http.ResponseWriter, obj interface{}, statusCode int) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	encoder := json.NewEncoder(w)
	return encoder.Encode(obj)
}

// Connect ControlEnvProxyServer
func ConnectControlEnvProxyServer(devId string, pool *DevicePool) (*grpc.ClientConn, error) {
	dev := pool.GetDevice(devId)
	if dev == nil {
		return nil, errors.New("Device not found")
	}

	devInfo := dev.privateData.(map[string]interface{})
	serverPath, ok := devInfo["control_env_proxy_server_path"].(string)
	if !ok {
		return nil, errors.New("ControlEnvProxyServer path not found")
	}
	return grpc.Dial("unix://"+serverPath, grpc.WithTransportCredentials(insecure.NewCredentials()))
}
