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

package keepclient

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"git.arvados.org/arvados.git/sdk/go/arvados"
)

// keepViaHTTP implements arvados.KeepGateway by using a KeepClient to
// do upstream requests to keepstore and keepproxy.
//
// This enables KeepClient to use KeepGateway wrappers (like
// arvados.DiskCache) to wrap its own HTTP client back-end methods
// (getOrHead, httpBlockWrite).
//
// See (*KeepClient)upstreamGateway() for the relevant glue.
type keepViaHTTP struct {
	*KeepClient
}

func (kvh *keepViaHTTP) ReadAt(locator string, dst []byte, offset int) (int, error) {
	rdr, _, _, _, err := kvh.getOrHead("GET", locator, nil)
	if err != nil {
		return 0, err
	}
	defer rdr.Close()
	_, err = io.CopyN(io.Discard, rdr, int64(offset))
	if err != nil {
		return 0, err
	}
	n, err := rdr.Read(dst)
	return int(n), err
}

func (kvh *keepViaHTTP) BlockRead(ctx context.Context, opts arvados.BlockReadOptions) (int, error) {
	if opts.CheckCacheOnly {
		return 0, arvados.ErrNotCached
	}
	rdr, _, _, _, err := kvh.getOrHead("GET", opts.Locator, nil)
	if err != nil {
		return 0, err
	}
	n, err := io.Copy(opts.WriteTo, rdr)
	errClose := rdr.Close()
	if err == nil {
		err = errClose
	}
	return int(n), err
}

func (kvh *keepViaHTTP) BlockWrite(ctx context.Context, req arvados.BlockWriteOptions) (arvados.BlockWriteResponse, error) {
	return kvh.httpBlockWrite(ctx, req)
}

func (kvh *keepViaHTTP) LocalLocator(locator string) (string, error) {
	if !strings.Contains(locator, "+R") {
		// Either it has +A, or it's unsigned and we assume
		// it's a local locator on a site with signatures
		// disabled.
		return locator, nil
	}
	sighdr := fmt.Sprintf("local, time=%s", time.Now().UTC().Format(time.RFC3339))
	_, _, url, hdr, err := kvh.KeepClient.getOrHead("HEAD", locator, http.Header{"X-Keep-Signature": []string{sighdr}})
	if err != nil {
		return "", err
	}
	loc := hdr.Get("X-Keep-Locator")
	if loc == "" {
		return "", fmt.Errorf("missing X-Keep-Locator header in HEAD response from %s", url)
	}
	return loc, nil
}
