package sfcrmappservice

import (
	"github.com/pingcap-inc/nexuscrm-app-packs/sfcrm/querycodec"
	layoutsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv2"
	historysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
)

type historyColumnSpec struct {
	name, label, fieldType string
	referenceTo            []string
	source                 historysemantic.HistoryColumn
	filterable, sortable   bool
}

// historyColumns is the CRM projection of the Runtime history result. Describe,
// related-list discovery, and Layout authoring consume this same definition.
func historyColumns(objectName string, parent searchObjectSpec) []historyColumnSpec {
	return []historyColumnSpec{
		{querycodec.HistoryIDField, "History ID", "id", nil, historysemantic.HistoryColumnID, false, false},
		{querycodec.HistoryParentFieldName(objectName), parent.Label, "reference", []string{parent.APIName}, historysemantic.HistoryColumnParentID, true, false},
		{querycodec.HistoryChangedField, "Field", "picklist", nil, historysemantic.HistoryColumnField, true, false},
		{querycodec.HistoryOldValueField, "Old Value", "anyType", nil, historysemantic.HistoryColumnOldValue, false, false},
		{querycodec.HistoryNewValueField, "New Value", "anyType", nil, historysemantic.HistoryColumnNewValue, false, false},
		{querycodec.HistoryDataTypeField, "Data Type", "string", nil, historysemantic.HistoryColumnDataType, false, false},
		{querycodec.HistoryCreatedDateField, "Created Date", "datetime", nil, historysemantic.HistoryColumnCreatedDate, false, true},
		{querycodec.HistoryCreatedByField, "Created By", "reference", []string{"User"}, historysemantic.HistoryColumnCreatedByID, false, false},
	}
}

// Projection assembly is pure application grammar. Runtime checks current
// physical schema, so saving never waits for a Catalog object-shape refresh.
func historyLayoutProjections(parentName string) []layoutsemantic.HistoryRelatedListProjection {
	if !historyParentNameSupportsDescribe(parentName) {
		return nil
	}
	objectName := querycodec.HistoryObjectName(parentName)
	columns := make(map[string]historysemantic.HistoryColumn)
	for _, field := range historyColumns(objectName, searchObjectSpec{APIName: parentName}) {
		columns[field.name] = field.source
	}
	return []layoutsemantic.HistoryRelatedListProjection{{ObjectID: objectName, Columns: columns}}
}

func historyRelatedListCandidate(parent searchObjectSpec, specs map[string]searchObjectSpec) (relatedListCandidate, bool) {
	name := querycodec.HistoryObjectName(parent.APIName)
	if _, found := virtualHistoryParent(name, specs); !found {
		return relatedListCandidate{}, false
	}
	lookup := ""
	fields := []string{}
	for _, field := range historyColumns(name, parent) {
		if field.source == historysemantic.HistoryColumnParentID {
			lookup = field.name
		}
		switch field.source {
		case historysemantic.HistoryColumnField, historysemantic.HistoryColumnOldValue, historysemantic.HistoryColumnNewValue, historysemantic.HistoryColumnCreatedDate, historysemantic.HistoryColumnCreatedByID:
			fields = append(fields, field.name)
		}
	}
	label := "History"
	if name == querycodec.OpportunityFieldHistoryObject {
		label = "Field History"
	}
	return relatedListCandidate{ID: name + "-" + lookup, ObjectAPIName: name, LookupField: lookup, Label: label, SecondaryLabel: "via " + parent.Label, FieldLabel: parent.Label, Fields: fields, Bucket: "system", IsSystem: true}, true
}
