package catalogreconcile

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"

	"github.com/nexuscrm/shared/pkg/models"
	consumerv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	"github.com/pingcap-inc/nexuscrm-controlplane/catalogapp"
)

const maxEffectiveApplications = 4096

type effectiveApplicationNavigationDocument struct {
	Applications []effectiveApplicationNavigationApplication `json:"applications"`
}

type effectiveApplicationNavigationApplication struct {
	ID              string                               `json:"id"`
	FrontendAppID   string                               `json:"frontendAppId,omitempty"`
	Label           string                               `json:"label"`
	Description     string                               `json:"description,omitempty"`
	Icon            string                               `json:"icon,omitempty"`
	Color           string                               `json:"color,omitempty"`
	NavigationItems []effectiveApplicationNavigationItem `json:"navigationItems"`
	UtilityItems    []effectiveApplicationUtilityItem    `json:"utilityItems"`
}

type effectiveApplicationNavigationItem struct {
	ID            string `json:"id"`
	Type          string `json:"type"`
	ObjectAPIName string `json:"objectApiName,omitempty"`
	PageURL       string `json:"pageUrl,omitempty"`
	DashboardID   string `json:"dashboardId,omitempty"`
	Label         string `json:"label"`
	Icon          string `json:"icon,omitempty"`
}

type effectiveApplicationUtilityItem struct {
	ID          string `json:"id"`
	Type        string `json:"type"`
	Label       string `json:"label"`
	Icon        string `json:"icon,omitempty"`
	PanelWidth  *int   `json:"panelWidth,omitempty"`
	PanelHeight *int   `json:"panelHeight,omitempty"`
}

func buildEffectiveApplicationNavigationComponent(
	applications []*models.AppConfig,
	objects []*models.ObjectMetadata,
) (catalogapp.EffectiveMetadataComponent, error) {
	if len(applications) > maxEffectiveApplications {
		return catalogapp.EffectiveMetadataComponent{}, fmt.Errorf(
			"effective application navigation exceeds the %d-application bound",
			maxEffectiveApplications,
		)
	}

	document := effectiveApplicationNavigationDocument{
		Applications: make([]effectiveApplicationNavigationApplication, 0, len(applications)),
	}
	seenApplications := make(map[string]struct{}, len(applications))
	for index, application := range applications {
		if application == nil {
			return catalogapp.EffectiveMetadataComponent{}, fmt.Errorf(
				"effective application navigation[%d] is nil", index,
			)
		}
		applicationID := strings.TrimSpace(application.ID)
		applicationKey := strings.ToLower(applicationID)
		if applicationID == "" {
			return catalogapp.EffectiveMetadataComponent{}, fmt.Errorf(
				"effective application navigation[%d] has no identity", index,
			)
		}
		if _, duplicate := seenApplications[applicationKey]; duplicate {
			return catalogapp.EffectiveMetadataComponent{}, fmt.Errorf(
				"effective application navigation contains duplicate application %q",
				applicationID,
			)
		}
		seenApplications[applicationKey] = struct{}{}
		projected := effectiveApplicationNavigationApplication{
			ID: applicationID, FrontendAppID: strings.TrimSpace(application.FrontendAppID),
			Label:       strings.TrimSpace(application.Label),
			Description: strings.TrimSpace(application.Description),
			Icon:        strings.TrimSpace(application.Icon), Color: strings.TrimSpace(application.Color),
			NavigationItems: make([]effectiveApplicationNavigationItem, 0),
			UtilityItems:    make([]effectiveApplicationUtilityItem, 0, len(application.UtilityItems)),
		}
		// Historical component shape is retained for envelope compatibility. Live
		// navigation is owned by Runtime and never influences this component digest.
		seenUtilityItems := make(map[string]struct{}, len(application.UtilityItems))
		for itemIndex, item := range application.UtilityItems {
			itemID := strings.TrimSpace(item.ID)
			itemType := strings.TrimSpace(item.Type)
			if itemID == "" || itemType == "" {
				return catalogapp.EffectiveMetadataComponent{}, fmt.Errorf(
					"effective application %q utility item[%d] has no identity or type",
					applicationID, itemIndex,
				)
			}
			itemKey := strings.ToLower(itemID)
			if _, duplicate := seenUtilityItems[itemKey]; duplicate {
				return catalogapp.EffectiveMetadataComponent{}, fmt.Errorf(
					"effective application %q contains duplicate utility item %q",
					applicationID, itemID,
				)
			}
			seenUtilityItems[itemKey] = struct{}{}
			projected.UtilityItems = append(projected.UtilityItems,
				effectiveApplicationUtilityItem{
					ID: itemID, Type: itemType, Label: strings.TrimSpace(item.Label),
					Icon: strings.TrimSpace(item.Icon), PanelWidth: item.PanelWidth,
					PanelHeight: item.PanelHeight,
				},
			)
		}
		document.Applications = append(document.Applications, projected)
	}
	sort.Slice(document.Applications, func(left, right int) bool {
		return document.Applications[left].ID < document.Applications[right].ID
	})
	encoded, err := json.Marshal(document)
	if err != nil {
		return catalogapp.EffectiveMetadataComponent{}, err
	}
	component := catalogapp.EffectiveMetadataComponent{
		ComponentKind:          consumerv1.EffectiveApplicationNavigationComponentKind,
		ComponentFormatVersion: 1,
		BusinessKey:            consumerv1.EffectiveApplicationNavigationComponentBusinessKey,
		ContentDigest:          consumerv1.ComputeEffectiveMetadataComponentDigest(encoded),
		CanonicalBehavior:      encoded,
	}
	return component, nil
}

var _ EffectiveApplicationNavigationMetadataReader = (*RepositoryMetadataReader)(nil)
