package indexer

import (
	"encoding/json"
	"errors"
	"time"
)

type DefaultValidator struct{}

func (v DefaultValidator) Validate(key string, value []byte) error {
	return nil
}

func (v DefaultValidator) Select(key string, values [][]byte) (int, error) {
	return 0, nil
}

type PeerRecordValidator struct{}

func (v PeerRecordValidator) Validate(key string, value []byte) error {
	// Accept valid tombstones — deletion must be storable so it can propagate
	// and win over stale live records on other DHT nodes via Select().
	var ts TombstoneRecord
	if err := json.Unmarshal(value, &ts); err == nil && ts.Tombstone {
		if ts.PeerID == "" || ts.DID == "" {
			return errors.New("tombstone: missing fields")
		}
		if time.Since(ts.DeletedAt) > tombstoneTTL {
			return errors.New("tombstone: expired")
		}
		if _, err := ts.Verify(); err != nil {
			return errors.New("tombstone: " + err.Error())
		}
		return nil
	}

	var rec PeerRecord
	if err := json.Unmarshal(value, &rec); err != nil {
		return errors.New("invalid json")
	}

	// PeerID must exist
	if rec.PeerID == "" {
		return errors.New("missing peerID")
	}

	// Expiry check
	if rec.ExpiryDate.Before(time.Now().UTC()) {
		return errors.New("record expired")
	}

	// TTL cap: publisher cannot set an expiry further than maxTTLSeconds in
	// the future. Prevents abuse (e.g. records designed to linger for years).
	if rec.ExpiryDate.After(time.Now().UTC().Add(maxTTLSeconds * time.Second)) {
		return errors.New("TTL exceeds maximum allowed")
	}

	// Signature verification
	if _, err := rec.Verify(); err != nil {
		return errors.New("invalid signature")
	}

	return nil
}

func (v PeerRecordValidator) Select(key string, values [][]byte) (int, error) {
	// Tombstone always wins: a signed delete supersedes any live record,
	// even if the live record has a later ExpiryDate.
	for i, val := range values {
		var ts TombstoneRecord
		if err := json.Unmarshal(val, &ts); err == nil && ts.Tombstone {
			return i, nil
		}
	}

	var newest time.Time
	index := 0

	for i, val := range values {
		var rec PeerRecord
		if err := json.Unmarshal(val, &rec); err != nil {
			continue
		}

		if rec.ExpiryDate.After(newest) {
			newest = rec.ExpiryDate
			index = i
		}
	}

	return index, nil
}
