package apiclient

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

// ConditionalGETResult carries the HTTP cache validator returned by one GET.
// NotModified is true only for a 304 response; callers must already own a
// complete cached representation before accepting it.
type ConditionalGETResult struct {
	ETag        string
	NotModified bool
}

// GetConditional sends an authenticated conditional GET. It preserves the
// ordinary GET authentication refresh and one-retry policy while exposing only
// the opaque ETag and 304 decision needed by catalog caching.
func (a *Client) GetConditional(
	ctx context.Context,
	path string,
	ifNoneMatch string,
	result any,
) (ConditionalGETResult, error) {
	var response ConditionalGETResult
	err := a.execute(ctx, "GET "+path, attemptReplaySafe, func() error {
		var err error
		response, err = a.doGetConditional(
			ctx,
			path,
			ifNoneMatch,
			result,
		)
		return err
	})
	return response, err
}

func (a *Client) doGetConditional(
	ctx context.Context,
	path string,
	ifNoneMatch string,
	result any,
) (ConditionalGETResult, error) {
	requestPath := a.requestPath(path)
	requestURL := a.ServerURL + requestPath
	req, err := http.NewRequestWithContext(
		ctx,
		http.MethodGet,
		requestURL,
		http.NoBody,
	)
	if err != nil {
		return ConditionalGETResult{},
			fmt.Errorf("agentteam api conditional get: %w", err)
	}
	a.setRequestHeaders(req, requestPath)
	if ifNoneMatch = strings.TrimSpace(ifNoneMatch); ifNoneMatch != "" {
		req.Header.Set("If-None-Match", ifNoneMatch)
	}

	resp, err := a.HTTPClient.Do(req)
	if err != nil {
		return ConditionalGETResult{},
			fmt.Errorf(
				"agentteam api conditional get: %w",
				&transportError{err: err},
			)
	}
	defer closeResponseBody(resp.Body)

	response := ConditionalGETResult{
		ETag:        strings.TrimSpace(resp.Header.Get("ETag")),
		NotModified: resp.StatusCode == http.StatusNotModified,
	}
	if response.NotModified {
		return response, nil
	}
	if resp.StatusCode >= 400 {
		return ConditionalGETResult{},
			apiErrorFromResponse(resp, http.MethodGet, requestPath)
	}
	if result != nil {
		if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
			return ConditionalGETResult{}, err
		}
	}
	return response, nil
}
