// Copyright (C) The Arvados Authors. All rights reserved.
//
// SPDX-License-Identifier: AGPL-3.0

package controller

import (
	"bytes"
	"crypto/sha256"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"git.arvados.org/arvados.git/lib/config"
	"git.arvados.org/arvados.git/sdk/go/arvadostest"
	"git.arvados.org/arvados.git/sdk/go/ctxlog"
	check "gopkg.in/check.v1"
)

var _ = check.Suite(&railsRestartSuite{})

type railsRestartSuite struct{}

// This tests RailsAPI, not controller -- but tests RailsAPI's
// integration with passenger, so it needs to run against the
// run-tests.sh environment where RailsAPI runs under passenger, not
// in the Rails test environment.
func (s *railsRestartSuite) TestConfigReload(c *check.C) {
	hc := http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}}

	confdata, err := os.ReadFile(os.Getenv("ARVADOS_CONFIG"))
	c.Assert(err, check.IsNil)
	oldhash := fmt.Sprintf("%x", sha256.Sum256(confdata))
	c.Logf("oldhash %s", oldhash)

	ldr := config.NewLoader(&bytes.Buffer{}, ctxlog.TestLogger(c))
	cfg, err := ldr.Load()
	c.Assert(err, check.IsNil)
	cc, err := cfg.GetCluster("")
	c.Assert(err, check.IsNil)
	var metricsURL string
	for u := range cc.Services.RailsAPI.InternalURLs {
		u := url.URL(u)
		mu, err := u.Parse("/metrics")
		c.Assert(err, check.IsNil)
		metricsURL = mu.String()
	}

	req, err := http.NewRequest(http.MethodGet, metricsURL, nil)
	c.Assert(err, check.IsNil)
	req.Header.Set("Authorization", "Bearer "+arvadostest.ManagementToken)

	resp, err := hc.Do(req)
	c.Assert(err, check.IsNil)
	c.Check(resp.StatusCode, check.Equals, http.StatusOK)
	body, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, check.IsNil)
	c.Check(string(body), check.Matches, `(?ms).*`+oldhash+`.*`)

	f, err := os.OpenFile(os.Getenv("ARVADOS_CONFIG"), os.O_WRONLY|os.O_APPEND, 0)
	c.Assert(err, check.IsNil)
	_, err = f.Write([]byte{'\n'})
	c.Assert(err, check.IsNil)
	err = f.Close()
	c.Assert(err, check.IsNil)
	newhash := fmt.Sprintf("%x", sha256.Sum256(append(confdata, '\n')))
	c.Logf("newhash %s", newhash)

	// Wait for RailsAPI's 1 Hz reload_config thread to poll and
	// hit restart.txt
	pollstart := time.Now()
	for deadline := time.Now().Add(20 * time.Second); time.Now().Before(deadline); time.Sleep(time.Second) {
		resp, err = hc.Do(req)
		c.Assert(err, check.IsNil)
		defer resp.Body.Close()
		c.Check(resp.StatusCode, check.Equals, http.StatusOK)
		body, err = ioutil.ReadAll(resp.Body)
		c.Assert(err, check.IsNil)
		resp.Body.Close()
		if strings.Contains(string(body), newhash) {
			break
		}
	}
	c.Logf("waited %s for rails to restart", time.Now().Sub(pollstart))
	c.Check(string(body), check.Matches, `(?ms).*`+newhash+`.*`)
}