package mfer

import (
	"bytes"
	"compress/gzip"
	"errors"
	"io"

	"git.eeqj.de/sneak/mfer/internal/bork"
	"git.eeqj.de/sneak/mfer/internal/log"
	"google.golang.org/protobuf/proto"
)

func (m *manifest) validateProtoOuter() error {
	if m.pbOuter.Version != MFFileOuter_VERSION_ONE {
		return errors.New("unknown version")
	}
	if m.pbOuter.CompressionType != MFFileOuter_COMPRESSION_GZIP {
		return errors.New("unknown compression type")
	}

	bb := bytes.NewBuffer(m.pbOuter.InnerMessage)

	gzr, err := gzip.NewReader(bb)
	if err != nil {
		return err
	}

	dat, err := io.ReadAll(gzr)
	defer gzr.Close()

	if err != nil {
		return err
	}

	isize := len(dat)
	if int64(isize) != m.pbOuter.Size {
		log.Debugf("truncated data, got %d expected %d", isize, m.pbOuter.Size)
		return bork.ErrFileTruncated
	}
	log.Debugf("inner data size is %d", isize)
	log.Dump(dat)
	log.Dump(m.pbOuter.Sha256)
	return nil
}

func validateMagic(dat []byte) bool {
	ml := len([]byte(MAGIC))
	if len(dat) < ml {
		return false
	}
	got := dat[0:ml]
	expected := []byte(MAGIC)
	return bytes.Equal(got, expected)
}

func NewFromProto(input io.Reader) (*manifest, error) {
	m := New()
	dat, err := io.ReadAll(input)
	if err != nil {
		return nil, err
	}
	if !validateMagic(dat) {
		return nil, errors.New("invalid file format")
	}

	// remove magic bytes prefix:
	ml := len([]byte(MAGIC))
	bb := bytes.NewBuffer(dat[ml:])
	dat = bb.Bytes()

	log.Dump(dat)

	// deserialize:
	m.pbOuter = new(MFFileOuter)
	err = proto.Unmarshal(dat, m.pbOuter)

	if err != nil {
		return nil, err
	}

	ve := m.validateProtoOuter()
	if ve != nil {
		return nil, ve
	}

	// FIXME TODO deserialize inner
	return m, nil
}
