package amzncorp

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"

	"github.com/aki237/nscjar"
)

func MidwayClient(cookieFile io.Reader) (*http.Client, error) {
	// curl can write out cookie file lines that don't include a value for the
	// cookie. nscjar can't handle those lines and will return an error.
	// Remove those lines before calling it.
	cookieBuf := new(bytes.Buffer)
	sc := bufio.NewScanner(cookieFile)
	sc.Split(bufio.ScanLines)
	for sc.Scan() {
		if !bytes.HasPrefix(sc.Bytes(), []byte("# ")) && len(bytes.Fields(sc.Bytes())) != 7 {
			continue
		}
		fmt.Fprintf(cookieBuf, "%s\n", sc.Bytes())
	}

	cookies, err := (&nscjar.Parser{}).Unmarshal(cookieBuf)
	if err != nil {
		return nil, err
	}

	jar, err := cookiejar.New(&cookiejar.Options{})
	if err != nil {
		return nil, err
	}

	for _, cookie := range cookies {
		// nscjar swaps the arguments to strings.HasPrefix; work around it.
		const httpOnlyPrefix = "#HttpOnly_"
		if strings.HasPrefix(cookie.Domain, httpOnlyPrefix) {
			cookie.Domain = strings.TrimPrefix(cookie.Domain, httpOnlyPrefix)
			cookie.HttpOnly = true
		}

		u := &url.URL{Scheme: "https", Host: cookie.Domain, Path: cookie.Path}
		jar.SetCookies(u, []*http.Cookie{cookie})
	}

	certs, err := AllCerts()
	if err != nil {
		return nil, err
	}
	rt := &http.Transport{
		TLSClientConfig: &tls.Config{
			RootCAs: certs,
		},
	}

	client := &http.Client{
		Jar:           jar,
		CheckRedirect: checkRedirect,
		Transport:     rt,
	}

	return client, nil
}

func checkRedirect(req *http.Request, via []*http.Request) error {
	// Redirects sometimes include an explicit port. Including a
	// specific port in the Host header causes some services
	// (isengard-service.amazon.com being one of them) to reject the
	// request.
	req.URL.Host = strings.TrimSuffix(req.URL.Host, ":443")

	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	return nil
}
