// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT

package objects

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"net/http"

	options_http "code.forgejo.org/f3/gof3/v3/options/http"
)

type SHASetter interface {
	SetSHA(sha string)
}

func FuncReadURLAndSetSHA(newHTTPClient options_http.NewMigrationHTTPClientFun, url string, sha SHASetter) func() io.ReadCloser {
	return func() io.ReadCloser {
		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			panic(err)
		}
		httpClient := newHTTPClient()
		resp, err := httpClient.Do(req)
		if err != nil {
			panic(fmt.Errorf("while downloading %s %w", url, err))
		}

		return FuncReadAndSetSHA(resp.Body, sha)()
	}
}

type readAndSetSHA struct {
	reader io.Reader
	closer io.Closer
	sha    SHASetter
	hasher hash.Hash
}

func (o *readAndSetSHA) Read(b []byte) (n int, err error) {
	return o.reader.Read(b)
}

func (o *readAndSetSHA) Close() error {
	o.sha.SetSHA(hex.EncodeToString(o.hasher.Sum(nil)))
	return o.closer.Close()
}

func newReadAndSetSHA(reader io.ReadCloser, sha SHASetter) *readAndSetSHA {
	hasher := sha256.New()
	return &readAndSetSHA{
		reader: io.TeeReader(reader, hasher),
		closer: reader,
		sha:    sha,
		hasher: hasher,
	}
}

func FuncReadAndSetSHA(reader io.ReadCloser, sha SHASetter) func() io.ReadCloser {
	return func() io.ReadCloser {
		return newReadAndSetSHA(reader, sha)
	}
}
