package odata

import (
	"strings"

	"github.com/CiscoM31/godata"
)

// GetExpandValues extracts the values of the $expand query parameter and
// returns them in a []string, rejecting any $expand value that consists of more
// than just a single path segment.
func GetExpandValues(req *godata.GoDataQuery) ([]string, error) {
	if req == nil || req.Expand == nil {
		return []string{}, nil
	}

	var expand []string
	for _, item := range req.Expand.ExpandItems {
		paths, err := collectExpandPaths(item, "")
		if err != nil {
			return nil, err
		}
		expand = append(expand, paths...)
	}

	return expand, nil
}

// collectExpandPaths recursively collects all valid expand paths from the given item.
func collectExpandPaths(item *godata.ExpandItem, prefix string) ([]string, error) {
	if err := validateExpandItem(item); err != nil {
		return nil, err
	}

	// Build the current path
	currentPath := prefix
	if len(item.Path) > 1 {
	   return nil, godata.NotImplementedError("multiple segments in $expand not supported")
	}
	if len(item.Path) == 1 {
		if currentPath == "" {
			currentPath = item.Path[0].Value
		} else {
			currentPath += "." + item.Path[0].Value
		}
	}

	// Collect all paths, including nested ones
	paths := []string{currentPath}
	if item.Expand != nil {
		for _, subItem := range item.Expand.ExpandItems {
			subPaths, err := collectExpandPaths(subItem, currentPath)
			if err != nil {
				return nil, err
			}
			paths = append(paths, subPaths...)
		}
	}

	return paths, nil
}

// validateExpandItem checks if an expand item contains unsupported options.
func validateExpandItem(item *godata.ExpandItem) error {
	if item.Filter != nil || item.At != nil || item.Search != nil ||
		item.OrderBy != nil || item.Skip != nil || item.Top != nil ||
		item.Select != nil || item.Compute != nil || item.Levels != 0 {
		return godata.NotImplementedError("options for $expand not supported")
	}
	return nil
}

// GetSelectValues extracts the values of the $select query parameter and
// returns them in a []string, rejects any $select value that consists of more
// than just a single path segment
func GetSelectValues(req *godata.GoDataQuery) ([]string, error) {
	if req == nil || req.Select == nil {
		return []string{}, nil
	}
	sel := make([]string, 0, len(req.Select.SelectItems))
	for _, item := range req.Select.SelectItems {
		if len(item.Segments) > 1 {
			return []string{}, godata.NotImplementedError("multiple segments in $select not supported")
		}
		sel = append(sel, item.Segments[0].Value)
	}
	return sel, nil
}

// GetSearchValues extracts the value of the $search query parameter and returns
// it as a string. Rejects any search query that is more than just a simple string
func GetSearchValues(req *godata.GoDataQuery) (string, error) {
	if req == nil || req.Search == nil {
		return "", nil
	}

	// Only allow simple search queries for now
	if len(req.Search.Tree.Children) != 0 {
		return "", godata.NotImplementedError("complex search queries are not supported")
	}

	searchValue := strings.Trim(req.Search.Tree.Token.Value, "\"")
	return searchValue, nil
}
