package archive

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger-test/once/repack/log"
	"github.com/pingcap/schrodinger-test/once/repack/util"
	"go.uber.org/zap"
)

const (
	FileServerEndpoint = "http://fileserver.pingcap.net"
	CIBuildPrefix      = "ci-build/"
)

var (
	ErrNotFound = errors.New("archive not found")
)

type Kind string

const (
	TiDB     Kind = "tidb"
	TiKV     Kind = "tikv"
	PD       Kind = "pd"
	TiDBTest Kind = "tidb-test"
)

type Ref struct {
	Kind Kind
	Tags []string
	Addr string
}

func (r Ref) DockerTags() []string {
	tags := make([]string, 0, len(r.Tags))
	for _, tag := range r.Tags {
		if util.MatchCommitHash(tag) {
			tag = tag[0:7]
		} else {
			tag = strings.Replace(tag, ":", "_", -1)
			tag = strings.Replace(tag, "/", "-", -1)
		}
		tags = append(tags, string(r.Kind)+":"+tag)
	}
	if len(tags) == 0 {
		tags = append(tags, string(r.Kind)+":latest")
	}
	return tags
}

func ResolveFromFileServer(kind Kind, tag string) (Ref, error) {

	hash, tags := tag, []string{tag}

	if !util.MatchCommitHash(hash) {
		res, err := http.Get(fmt.Sprintf(FileServerEndpoint+"/download/refs/pingcap/%s/%s/sha1", kind, tag))
		if err != nil {
			return Ref{}, errors.Trace(err)
		}
		defer res.Body.Close()
		if res.StatusCode == http.StatusOK {
			bs, err := ioutil.ReadAll(res.Body)
			if err != nil {
				return Ref{}, errors.Trace(err)
			}
			hash = strings.TrimSpace(string(bs))
			if i := strings.LastIndex(hash, "/"); i > 0 {
				tags = append(tags, hash[i+1:])
			} else {
				tags = append(tags, hash)
			}
		}
	}

	checkRef := func(url string) (Ref, error) {
		res, err := http.Head(url)
		if err != nil {
			return Ref{}, errors.Trace(err)
		}
		defer res.Body.Close()
		if res.StatusCode != http.StatusOK {
			log.Info("unexpected status code",
				zap.Int("code", res.StatusCode),
				zap.String("url", url),
			)
			return Ref{}, errors.Trace(ErrNotFound)
		}
		return Ref{Kind: CIBuildPrefix + kind, Tags: tags, Addr: url}, nil
	}

	switch kind {
	case TiDB, TiKV, PD:
		return checkRef(fmt.Sprintf(FileServerEndpoint+"/download/builds/pingcap/%s/%s/centos7/%s-server.tar.gz", kind, hash, kind))
	default:
		return checkRef(fmt.Sprintf(FileServerEndpoint+"/download/builds/pingcap/%s/%s/centos7/%s.tar.gz", kind, hash, kind))
	}
}
