package shared

import (
	"bytes"
	"context"
	"fmt"

	"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
)

// PrepareChunkExtraction validates common D&D extraction prerequisites and
// prepares owned chunk-scoped source material for prompt inputs.
func PrepareChunkExtraction(ctx context.Context, req contracts.TypedExtractionRequest) (contracts.LLMInputMaterial, error) {
	if ctx == nil {
		return contracts.LLMInputMaterial{}, fmt.Errorf("context must not be nil")
	}
	if err := ctx.Err(); err != nil {
		return contracts.LLMInputMaterial{}, fmt.Errorf("context error before extraction: %w", err)
	}
	if req.Source == nil {
		return contracts.LLMInputMaterial{}, fmt.Errorf("source must not be nil")
	}
	if req.Chunk == nil {
		return contracts.LLMInputMaterial{}, fmt.Errorf("chunk must not be nil")
	}
	if len(req.Chunk.Units) == 0 {
		return contracts.LLMInputMaterial{}, fmt.Errorf("chunk %q units must not be empty", req.Chunk.ID)
	}
	material := req.SourceInput.Clone()
	if len(material.Content) == 0 {
		material = contracts.NewLLMInputMaterial("source", req.Chunk.MediaType, req.Chunk.Content, "", "")
	}
	if !bytes.Equal(material.Content, req.Chunk.Content) {
		return contracts.LLMInputMaterial{}, fmt.Errorf("source input must match chunk %q content", req.Chunk.ID)
	}
	if material.Name == "" {
		material.Name = "source"
	}
	if material.MediaType == "" {
		material.MediaType = req.Chunk.MediaType
	}
	if material.SizeBytes == 0 {
		material.SizeBytes = int64(len(material.Content))
	}
	return material, nil
}
