// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0

package jsonpath

import (
	"bytes"
	"fmt"
	"strings"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/client-go/util/jsonpath"
)

const maxJSONPathLength = 1024

// CompiledJSONPath wraps a parsed JSONPath expression for repeated use.
type CompiledJSONPath struct {
	jp *jsonpath.JSONPath
}

// CompileJSONPath parses and validates a JSONPath source path once.
// Example sourcePath: ".spec.resources.requests.cpu".
func CompileJSONPath(sourcePath string) (*CompiledJSONPath, error) {
	sourcePath = strings.TrimSpace(sourcePath)
	if err := validateSourcePath(sourcePath); err != nil {
		return nil, err
	}

	j := jsonpath.New("usagePath")
	j.AllowMissingKeys(true)

	if err := j.Parse(wrapJSONPath(sourcePath)); err != nil {
		return nil, fmt.Errorf("parse usage jsonpath %q: %w", sourcePath, err)
	}

	return &CompiledJSONPath{jp: j}, nil
}

// Execute applies a precompiled JSONPath to the given object and returns the extracted value.
func (c *CompiledJSONPath) Execute(u unstructured.Unstructured) (string, error) {
	if c == nil || c.jp == nil {
		return "", fmt.Errorf("compiled jsonpath is nil")
	}

	var buf bytes.Buffer
	if err := c.jp.Execute(&buf, u.Object); err != nil {
		return "", fmt.Errorf("execute usage jsonpath: %w", err)
	}

	return strings.TrimSpace(buf.String()), nil
}
