package fields

import (
	"bytes"
	"io"
	"log/slog"
	"net/http"

	"github.com/SigNoz/signoz/pkg/http/render"
	"github.com/SigNoz/signoz/pkg/telemetrylogs"
	"github.com/SigNoz/signoz/pkg/telemetrymetadata"
	"github.com/SigNoz/signoz/pkg/telemetrymetrics"
	"github.com/SigNoz/signoz/pkg/telemetrystore"
	"github.com/SigNoz/signoz/pkg/telemetrytraces"
	"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)

type API struct {
	telemetryStore         telemetrystore.TelemetryStore
	telemetryMetadataStore telemetrytypes.MetadataStore
}

func NewAPI(telemetryStore telemetrystore.TelemetryStore, logger *slog.Logger) *API {
	telemetryMetadataStore := telemetrymetadata.NewTelemetryMetaStore(
		logger,
		telemetryStore,
		telemetrytraces.DBName,
		telemetrytraces.TagAttributesV2TableName,
		telemetrytraces.SpanIndexV3TableName,
		telemetrymetrics.DBName,
		telemetrymetrics.AttributesMetadataTableName,
		telemetrylogs.DBName,
		telemetrylogs.LogsV2TableName,
		telemetrylogs.TagAttributesV2TableName,
		telemetrymetadata.DBName,
		telemetrymetadata.AttributesMetadataLocalTableName,
	)

	return &API{
		telemetryStore:         telemetryStore,
		telemetryMetadataStore: telemetryMetadataStore,
	}
}

func (api *API) GetFieldsKeys(w http.ResponseWriter, r *http.Request) {

	type fieldKeysResponse struct {
		Keys     map[string][]*telemetrytypes.TelemetryFieldKey `json:"keys"`
		Complete bool                                           `json:"complete"`
	}

	bodyBytes, _ := io.ReadAll(r.Body)
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
	ctx := r.Context()

	fieldKeySelector, err := parseFieldKeyRequest(r)
	if err != nil {
		render.Error(w, err)
		return
	}

	keys, err := api.telemetryMetadataStore.GetKeys(ctx, fieldKeySelector)
	if err != nil {
		render.Error(w, err)
		return
	}

	response := fieldKeysResponse{
		Keys:     keys,
		Complete: len(keys) < fieldKeySelector.Limit,
	}

	render.Success(w, http.StatusOK, response)
}

func (api *API) GetFieldsValues(w http.ResponseWriter, r *http.Request) {

	type fieldValuesResponse struct {
		Values   *telemetrytypes.TelemetryFieldValues `json:"values"`
		Complete bool                                 `json:"complete"`
	}

	bodyBytes, _ := io.ReadAll(r.Body)
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
	ctx := r.Context()

	fieldValueSelector, err := parseFieldValueRequest(r)
	if err != nil {
		render.Error(w, err)
		return
	}

	allValues, err := api.telemetryMetadataStore.GetAllValues(ctx, fieldValueSelector)
	if err != nil {
		render.Error(w, err)
		return
	}

	relatedValues, err := api.telemetryMetadataStore.GetRelatedValues(ctx, fieldValueSelector)
	if err != nil {
		// we don't want to return error if we fail to get related values for some reason
		relatedValues = []string{}
	}

	values := &telemetrytypes.TelemetryFieldValues{
		StringValues:  allValues.StringValues,
		NumberValues:  allValues.NumberValues,
		RelatedValues: relatedValues,
	}

	response := fieldValuesResponse{
		Values: values,
		Complete: len(values.StringValues) < fieldValueSelector.Limit &&
			len(values.BoolValues) < fieldValueSelector.Limit &&
			len(values.NumberValues) < fieldValueSelector.Limit &&
			len(values.RelatedValues) < fieldValueSelector.Limit,
	}

	render.Success(w, http.StatusOK, response)
}
