// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// SPDX-License-Identifier: EUPL-1.2

package chain

import (
	"bytes"
	"fmt"

	coreerr "dappco.re/go/core/log"

	"dappco.re/go/core/blockchain/config"
	"dappco.re/go/core/blockchain/consensus"
	"dappco.re/go/core/blockchain/types"
	"dappco.re/go/core/blockchain/wire"
)

// ValidateHeader checks a block header before storage.
// expectedHeight is the height at which this block would be stored.
func (c *Chain) ValidateHeader(b *types.Block, expectedHeight uint64, forks []config.HardFork) error {
	currentHeight, err := c.Height()
	if err != nil {
		return coreerr.E("Chain.ValidateHeader", "validate: get height", err)
	}

	// Height sequence check.
	if expectedHeight != currentHeight {
		return coreerr.E("Chain.ValidateHeader", fmt.Sprintf("validate: expected height %d but chain is at %d", expectedHeight, currentHeight), nil)
	}

	// Genesis block: prev_id must be zero.
	if expectedHeight == 0 {
		if !b.PrevID.IsZero() {
			return coreerr.E("Chain.ValidateHeader", "validate: genesis block has non-zero prev_id", nil)
		}
		if err := consensus.CheckBlockVersion(b.MajorVersion, forks, expectedHeight); err != nil {
			return coreerr.E("Chain.ValidateHeader", "validate: block version", err)
		}
		return nil
	}

	// Non-genesis: prev_id must match top block hash.
	_, topMeta, err := c.TopBlock()
	if err != nil {
		return coreerr.E("Chain.ValidateHeader", "validate: get top block", err)
	}
	if b.PrevID != topMeta.Hash {
		return coreerr.E("Chain.ValidateHeader", fmt.Sprintf("validate: prev_id %s does not match top block %s", b.PrevID, topMeta.Hash), nil)
	}

	// Block major version check.
	if err := consensus.CheckBlockVersion(b.MajorVersion, forks, expectedHeight); err != nil {
		return coreerr.E("Chain.ValidateHeader", "validate: block version", err)
	}

	// Block size check.
	var buf bytes.Buffer
	enc := wire.NewEncoder(&buf)
	wire.EncodeBlock(enc, b)
	if enc.Err() == nil && uint64(buf.Len()) > config.MaxBlockSize {
		return coreerr.E("Chain.ValidateHeader", fmt.Sprintf("validate: block size %d exceeds max %d", buf.Len(), config.MaxBlockSize), nil)
	}

	return nil
}
