// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.

package source

import (
_	"context"
_	"encoding/json"
	"fmt"
_	"gopkg.in/yaml.v3"
	"net/url"
	"net/http"
_	"path/filepath"
	"decl/internal/resource"
	"decl/internal/iofilter"
	"decl/internal/signature"
_	"os"
	"io"
	"errors"
	"crypto/sha256"
)

type HTTP struct {
	Endpoint string `yaml:"endpoint" json:"endpoint"`
}

func NewHTTP() *HTTP {
	return &HTTP{}
}

func init() {
	SourceTypes.Register([]string{"http","https"}, func(u *url.URL) DocSource {
		t := NewHTTP()
		t.Endpoint = u.String()
		return t
	})
}

func (d *HTTP) Type() string { return "http" }

func (h *HTTP) ExtractResources(filter ResourceSelector) ([]*resource.Document, error) {
	documents := make([]*resource.Document, 0, 100)

	resp, err := http.Get(h.Endpoint)
	if err != nil {
		return documents, err
	}
	defer resp.Body.Close()
	documentSignature := resp.Header.Get("Signature")
	if documentSignature == "" {
		signatureResp, signatureErr := http.Get(fmt.Sprintf("%s.sig", h.Endpoint))
		if signatureErr == nil {
			defer signatureResp.Body.Close()
			readSignatureBody, readSignatureErr := io.ReadAll(resp.Body)
			if readSignatureErr == nil {
				documentSignature = string(readSignatureBody)
			}
		}
	}

	hash := sha256.New()
	sumReadData := iofilter.NewReader(resp.Body, func(p []byte, readn int, readerr error) (n int, err error) {
		hash.Write(p)
		return 
	})

	decoder := resource.NewYAMLDecoder(sumReadData)
	index := 0
	for {
		doc := resource.NewDocument()
		e := decoder.Decode(doc)
		if errors.Is(e, io.EOF) {
			break
		}
		if e != nil {
			return documents, e
		}
		if validationErr := doc.Validate(); validationErr != nil {
			return documents, validationErr
		}
		documents = append(documents, doc)
		index++
	}

	if documentSignature != "" {
		sig := &signature.Ident{}
		sigErr := sig.VerifySum(hash.Sum(nil), []byte(documentSignature))
		if sigErr != nil {
			return documents, sigErr
		}
	}

	return documents, nil
}
