package suite

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"regexp"
)

type meData struct {
	ID     string  `json:"id"`
	Name   string  `json:"name"`
	Email  string  `json:"email"`
	Realms []realm `json:"realms"`
}

type realm struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	TenantID string `json:"tenantId"`
}

var csrfRegexp = regexp.MustCompile(`name="csrf" value="([0-9a-f]+)"`)

func (s *Suite) Login(email, password, tenant string) error {
	req, _ := http.NewRequest(http.MethodGet, s.PlatformURL("/auth/login/"+tenantSlug), nil)
	resp, err := s.Do(req)
	if err != nil {
		return fmt.Errorf("login request failed: %w", err)
	}
	defer resp.Body.Close()
	buf := &bytes.Buffer{}
	_, err = io.Copy(buf, resp.Body)
	if err != nil {
		return fmt.Errorf("can not copy response body: %w", err)
	}
	matches := csrfRegexp.FindSubmatch(buf.Bytes())
	if len(matches) != 2 {
		return errors.New("can not find csrf token in login page")
	}
	token := string(matches[1])
	values := url.Values{
		"email":    {email},
		"password": {password},
		"csrf":     {token},
	}
	if tenant != "" {
		values["tenant"] = []string{tenant}
	}
	resp, err = s.PostForm(s.PlatformURL("/auth/login/"+tenantSlug), values)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	u, _ := url.Parse(s.PlatformURL(""))
	cookies := s.Client.Jar.Cookies(u)
	for _, cookie := range cookies {
		if cookie.Name == "double-cookie" {
			s.doubleCookie = cookie.Value
			s.currentUser = email
		}
	}
	req, _ = http.NewRequest(http.MethodGet, s.PlatformURL("/auth/api/v2/me"), nil)
	resp, err = s.Do(req)
	if err != nil {
		return fmt.Errorf("me request failed: %w", err)
	}
	defer resp.Body.Close()

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("can not read me response: %w", err)
	}

	body := bytes.NewReader(b)

	data := meData{}
	if err = json.NewDecoder(body).Decode(&data); err != nil {
		body.Seek(0, io.SeekStart)
		io.Copy(os.Stdout, body)
		return fmt.Errorf("can not parse me response: %w", err)
	}
	s.Require().True(len(data.Realms) >= 1)
	s.ProjectID = data.Realms[0].ID
	s.TenantID = data.Realms[0].TenantID
	return nil
}
