// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package devices

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

// PDUConn encapsultes PDU connection settings.
type PDUConn struct {
	// Client is the client used to perform all requests.
	Client *http.Client

	// Host is the network hostname of the PDU.
	Host string

	// Username is the username by which we can log in to the PDU.
	Username string

	// Password is the password by which we can log in to the PDU.
	Password string

	// token is the authentication token obtained by Login.
	token string
}

type message struct {
	ID    int             `json:"msgid,omitempty"`
	Reply string          `json:"reply,omitempty"`
	Data  json.RawMessage `json:"data,omitempty"`
	Error struct {
		Name    string `json:"name"`
		Message string `json:"message"`
		Status  int    `json:"status"`
	} `json:"error,omitempty"`
}

// NewPDUConn initializes and returns a new PDUConn struct.
func NewPDUConn(host string, uname string, pwd string) *PDUConn {
	return &PDUConn{
		Client: &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		},
		Host:     host,
		Username: uname,
		Password: pwd,
	}
}

// Login performs a login and obtains authorization token used for other calls.
func (c *PDUConn) Login() error {
	q := make(url.Values)
	q.Set("username", c.Username)
	q.Set("password", c.Password)

	u := url.URL{
		Scheme:   "https",
		Host:     c.Host,
		Path:     "/api/AuthenticationControllers/login",
		RawQuery: q.Encode(),
	}

	l := struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}{
		Username: c.Username,
		Password: c.Password,
	}

	b := new(bytes.Buffer)
	if err := json.NewEncoder(b).Encode(l); err != nil {
		return err
	}

	req, err := http.NewRequest("POST", u.String(), b)
	req.Header.Add("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		return err
	}
	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var msg message
	err = json.NewDecoder(resp.Body).Decode(&msg)

	if resp.StatusCode != http.StatusCreated {
		if err != nil {
			return fmt.Errorf("request failed: %d", resp.StatusCode)
		} else {
			return fmt.Errorf("request failed: %s", msg.Error.Message)
		}
	}

	if token, ok := resp.Header["Authorization"]; ok {
		c.token = token[0]
	}

	return nil
}

// PDUReboot powercycles the given outlet.
func PDUReboot(outlet int, host string, uname string, pwd string) error {
	conn := NewPDUConn(host, uname, pwd)
	if err := conn.Login(); err != nil {
		return err
	}
	defer conn.Logout()
	return conn.Loads(outlet, "Cycle")
}

// Loads changes the outlet state.
func (c *PDUConn) Loads(outlet int, state string) error {
	u := url.URL{
		Scheme: "https",
		Host:   c.Host,
		Path:   fmt.Sprintf("/api/device/loads/%d", outlet),
	}

	s := struct {
		LoadFireState string `json:"loadFireState"`
	}{
		LoadFireState: state,
	}

	b := new(bytes.Buffer)
	if err := json.NewEncoder(b).Encode(s); err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", u.String(), b)
	if err != nil {
		return err
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Authorization", c.token)
	req.Header.Set("Content-Type", "application/json")
	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var msg message
	err = json.NewDecoder(resp.Body).Decode(&msg)

	if resp.StatusCode != http.StatusOK {
		if err != nil {
			return fmt.Errorf("request failed: %d", resp.StatusCode)
		} else {
			return fmt.Errorf("request failed: %s", msg.Error.Message)
		}
	}

	return nil
}

// Logout performs a logout and discards the authorization token.
func (c *PDUConn) Logout() error {
	u := url.URL{
		Scheme: "https",
		Host:   c.Host,
		Path:   "/api/AuthenticationControllers/logout",
	}

	req, err := http.NewRequest("POST", u.String(), nil)
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Authorization", c.token)
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		return err
	}
	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var msg message
	err = json.NewDecoder(resp.Body).Decode(&msg)

	if resp.StatusCode != http.StatusOK {
		if err != nil {
			return fmt.Errorf("request failed: %d", resp.StatusCode)
		} else {
			return fmt.Errorf("request failed: %s", msg.Error.Message)
		}
	}

	c.token = ""

	return nil
}
