package preproc

import (
	"fmt"
	"os"
	"strings"
)

// HybridFileReader implements FileReader with support for both embedded
// standard library (when C65LIBPATH is not set) and disk-based includes.
type HybridFileReader struct {
	diskReader    *DiskFileReader  // For relative includes & C65LIBPATH overrides
	libPath       string           // From C65LIBPATH env var
	usedEmbedded  bool             // Track if we've used embedded library
	embeddedCache map[string][]string // Cache for embedded files
}

// NewHybridFileReader creates a new HybridFileReader.
func NewHybridFileReader() *HybridFileReader {
	return &HybridFileReader{
		diskReader:    NewDiskFileReader(),
		libPath:       os.Getenv("C65LIBPATH"),
		embeddedCache: make(map[string][]string),
	}
}

// ReadLines implements the FileReader interface.
func (h *HybridFileReader) ReadLines(includeSpec string, currentDir string) ([]string, string, error) {
	// Check if this is an angle-bracket include
	if strings.HasPrefix(includeSpec, "<") && strings.HasSuffix(includeSpec, ">") {
		// If C65LIBPATH is set, delegate to DiskFileReader
		if h.libPath != "" {
			return h.diskReader.ReadLines(includeSpec, currentDir)
		}
		
		// Otherwise, use embedded library
		if !h.usedEmbedded {
			h.usedEmbedded = true
			// Note: Library source message is printed by NewDefaultFileReader factory
		}
		
		return h.readEmbeddedLibrary(includeSpec)
	}
	
	// Relative includes always go to disk
	return h.diskReader.ReadLines(includeSpec, currentDir)
}

// readEmbeddedLibrary reads a file from the embedded standard library.
func (h *HybridFileReader) readEmbeddedLibrary(spec string) ([]string, string, error) {
	// Convert angle-bracket spec to embedded path
	embeddedPath, err := embeddedLibPath(spec)
	if err != nil {
		return nil, "", err
	}
	
	// Check cache
	if lines, ok := h.embeddedCache[embeddedPath]; ok {
		// Return cached lines with virtual path for error messages
		return lines, "<embedded>/" + strings.TrimPrefix(embeddedPath, "lib/"), nil
	}
	
	// Read from embedded filesystem
	lines, err := readEmbeddedFile(embeddedPath)
	if err != nil {
		return nil, "", fmt.Errorf("embedded library include not found: %s", spec)
	}
	
	// Cache the result
	h.embeddedCache[embeddedPath] = lines
	
	// Return with virtual path for error messages
	return lines, "<embedded>/" + strings.TrimPrefix(embeddedPath, "lib/"), nil
}