package localdb

import (
	"encoding/json"
	"fmt"
	"sort"
	"time"
)

// BuildConfigurationSnapshot serializes the full local configuration state.
func BuildConfigurationSnapshot(localCfg *LocalConfiguration) (string, error) {
	snapshot := map[string]interface{}{
		"id":                      localCfg.ID,
		"uuid":                    localCfg.UUID,
		"server_id":               localCfg.ServerID,
		"project_uuid":            localCfg.ProjectUUID,
		"current_version_id":      localCfg.CurrentVersionID,
		"is_active":               localCfg.IsActive,
		"name":                    localCfg.Name,
		"items":                   localCfg.Items,
		"total_price":             localCfg.TotalPrice,
		"custom_price":            localCfg.CustomPrice,
		"notes":                   localCfg.Notes,
		"is_template":             localCfg.IsTemplate,
		"server_count":            localCfg.ServerCount,
		"server_model":            localCfg.ServerModel,
		"support_code":            localCfg.SupportCode,
		"article":                 localCfg.Article,
		"pricelist_id":            localCfg.PricelistID,
		"warehouse_pricelist_id":  localCfg.WarehousePricelistID,
		"competitor_pricelist_id": localCfg.CompetitorPricelistID,
		"disable_price_refresh":   localCfg.DisablePriceRefresh,
		"only_in_stock":           localCfg.OnlyInStock,
		"vendor_spec":             localCfg.VendorSpec,
		"line":                    localCfg.Line,
		"price_updated_at":        localCfg.PriceUpdatedAt,
		"created_at":              localCfg.CreatedAt,
		"updated_at":              localCfg.UpdatedAt,
		"synced_at":               localCfg.SyncedAt,
		"sync_status":             localCfg.SyncStatus,
		"original_user_id":        localCfg.OriginalUserID,
		"original_username":       localCfg.OriginalUsername,
	}

	data, err := json.Marshal(snapshot)
	if err != nil {
		return "", fmt.Errorf("marshal configuration snapshot: %w", err)
	}
	return string(data), nil
}

// DecodeConfigurationSnapshot returns editable fields from one saved snapshot.
func DecodeConfigurationSnapshot(data string) (*LocalConfiguration, error) {
	var snapshot struct {
		ProjectUUID           *string          `json:"project_uuid"`
		IsActive              *bool            `json:"is_active"`
		Name                  string           `json:"name"`
		Items                 LocalConfigItems `json:"items"`
		TotalPrice            *float64         `json:"total_price"`
		CustomPrice           *float64         `json:"custom_price"`
		Notes                 string           `json:"notes"`
		IsTemplate            bool             `json:"is_template"`
		ServerCount           int              `json:"server_count"`
		ServerModel           string           `json:"server_model"`
		SupportCode           string           `json:"support_code"`
		Article               string           `json:"article"`
		PricelistID           *uint            `json:"pricelist_id"`
		WarehousePricelistID  *uint            `json:"warehouse_pricelist_id"`
		CompetitorPricelistID *uint            `json:"competitor_pricelist_id"`
		DisablePriceRefresh   bool             `json:"disable_price_refresh"`
		OnlyInStock           bool             `json:"only_in_stock"`
		VendorSpec            VendorSpec       `json:"vendor_spec"`
		Line                  int              `json:"line"`
		PriceUpdatedAt        *time.Time       `json:"price_updated_at"`
		OriginalUserID        uint             `json:"original_user_id"`
		OriginalUsername      string           `json:"original_username"`
	}

	if err := json.Unmarshal([]byte(data), &snapshot); err != nil {
		return nil, fmt.Errorf("unmarshal snapshot JSON: %w", err)
	}

	isActive := true
	if snapshot.IsActive != nil {
		isActive = *snapshot.IsActive
	}

	return &LocalConfiguration{
		IsActive:              isActive,
		ProjectUUID:           snapshot.ProjectUUID,
		Name:                  snapshot.Name,
		Items:                 snapshot.Items,
		TotalPrice:            snapshot.TotalPrice,
		CustomPrice:           snapshot.CustomPrice,
		Notes:                 snapshot.Notes,
		IsTemplate:            snapshot.IsTemplate,
		ServerCount:           snapshot.ServerCount,
		ServerModel:           snapshot.ServerModel,
		SupportCode:           snapshot.SupportCode,
		Article:               snapshot.Article,
		PricelistID:           snapshot.PricelistID,
		WarehousePricelistID:  snapshot.WarehousePricelistID,
		CompetitorPricelistID: snapshot.CompetitorPricelistID,
		DisablePriceRefresh:   snapshot.DisablePriceRefresh,
		OnlyInStock:           snapshot.OnlyInStock,
		VendorSpec:            snapshot.VendorSpec,
		Line:                  snapshot.Line,
		PriceUpdatedAt:        snapshot.PriceUpdatedAt,
		OriginalUserID:        snapshot.OriginalUserID,
		OriginalUsername:      snapshot.OriginalUsername,
	}, nil
}

type configurationSpecPriceFingerprint struct {
	Items                 []configurationSpecPriceFingerprintItem `json:"items"`
	ServerCount           int                                     `json:"server_count"`
	TotalPrice            *float64                                `json:"total_price,omitempty"`
	CustomPrice           *float64                                `json:"custom_price,omitempty"`
	PricelistID           *uint                                   `json:"pricelist_id,omitempty"`
	WarehousePricelistID  *uint                                   `json:"warehouse_pricelist_id,omitempty"`
	CompetitorPricelistID *uint                                   `json:"competitor_pricelist_id,omitempty"`
	DisablePriceRefresh   bool                                    `json:"disable_price_refresh"`
	OnlyInStock           bool                                    `json:"only_in_stock"`
	VendorSpec            VendorSpec                              `json:"vendor_spec,omitempty"`
}

type configurationSpecPriceFingerprintItem struct {
	LotName   string  `json:"lot_name"`
	Quantity  int     `json:"quantity"`
	UnitPrice float64 `json:"unit_price"`
}

// BuildConfigurationSpecPriceFingerprint returns a stable JSON key based on
// spec + price fields only, used for revision deduplication.
func BuildConfigurationSpecPriceFingerprint(localCfg *LocalConfiguration) (string, error) {
	items := make([]configurationSpecPriceFingerprintItem, 0, len(localCfg.Items))
	for _, item := range localCfg.Items {
		items = append(items, configurationSpecPriceFingerprintItem{
			LotName:   item.LotName,
			Quantity:  item.Quantity,
			UnitPrice: item.UnitPrice,
		})
	}
	sort.Slice(items, func(i, j int) bool {
		if items[i].LotName != items[j].LotName {
			return items[i].LotName < items[j].LotName
		}
		if items[i].Quantity != items[j].Quantity {
			return items[i].Quantity < items[j].Quantity
		}
		return items[i].UnitPrice < items[j].UnitPrice
	})

	payload := configurationSpecPriceFingerprint{
		Items:                 items,
		ServerCount:           localCfg.ServerCount,
		TotalPrice:            localCfg.TotalPrice,
		CustomPrice:           localCfg.CustomPrice,
		PricelistID:           localCfg.PricelistID,
		WarehousePricelistID:  localCfg.WarehousePricelistID,
		CompetitorPricelistID: localCfg.CompetitorPricelistID,
		DisablePriceRefresh:   localCfg.DisablePriceRefresh,
		OnlyInStock:           localCfg.OnlyInStock,
		VendorSpec:            localCfg.VendorSpec,
	}

	raw, err := json.Marshal(payload)
	if err != nil {
		return "", fmt.Errorf("marshal spec+price fingerprint: %w", err)
	}
	return string(raw), nil
}
