package localdb

import (
	"time"

	"git.mchus.pro/mchus/quoteforge/internal/models"
)

// ConfigurationToLocal converts models.Configuration to LocalConfiguration
func ConfigurationToLocal(cfg *models.Configuration) *LocalConfiguration {
	items := make(LocalConfigItems, len(cfg.Items))
	for i, item := range cfg.Items {
		items[i] = LocalConfigItem{
			LotName:   item.LotName,
			Quantity:  item.Quantity,
			UnitPrice: item.UnitPrice,
		}
	}

	local := &LocalConfiguration{
		UUID:                  cfg.UUID,
		ProjectUUID:           cfg.ProjectUUID,
		IsActive:              true,
		Name:                  cfg.Name,
		Items:                 items,
		TotalPrice:            cfg.TotalPrice,
		CustomPrice:           cfg.CustomPrice,
		Notes:                 cfg.Notes,
		IsTemplate:            cfg.IsTemplate,
		ServerCount:           cfg.ServerCount,
		ServerModel:           cfg.ServerModel,
		SupportCode:           cfg.SupportCode,
		Article:               cfg.Article,
		PricelistID:           cfg.PricelistID,
		WarehousePricelistID:  cfg.WarehousePricelistID,
		CompetitorPricelistID: cfg.CompetitorPricelistID,
		ConfigType:            cfg.ConfigType,
		VendorSpec:            modelVendorSpecToLocal(cfg.VendorSpec),
		DisablePriceRefresh:   cfg.DisablePriceRefresh,
		OnlyInStock:           cfg.OnlyInStock,
		Line:                  cfg.Line,
		PriceUpdatedAt:        cfg.PriceUpdatedAt,
		CreatedAt:             cfg.CreatedAt,
		UpdatedAt:             time.Now(),
		SyncStatus:            "pending",
		OriginalUserID:        derefUint(cfg.UserID),
		OriginalUsername:      cfg.OwnerUsername,
	}

	if cfg.ID > 0 {
		serverID := cfg.ID
		local.ServerID = &serverID
	}

	return local
}

// LocalToConfiguration converts LocalConfiguration to models.Configuration
func LocalToConfiguration(local *LocalConfiguration) *models.Configuration {
	items := make(models.ConfigItems, len(local.Items))
	for i, item := range local.Items {
		items[i] = models.ConfigItem{
			LotName:   item.LotName,
			Quantity:  item.Quantity,
			UnitPrice: item.UnitPrice,
		}
	}

	cfg := &models.Configuration{
		UUID:                  local.UUID,
		OwnerUsername:         local.OriginalUsername,
		ProjectUUID:           local.ProjectUUID,
		Name:                  local.Name,
		Items:                 items,
		TotalPrice:            local.TotalPrice,
		CustomPrice:           local.CustomPrice,
		Notes:                 local.Notes,
		IsTemplate:            local.IsTemplate,
		ServerCount:           local.ServerCount,
		ServerModel:           local.ServerModel,
		SupportCode:           local.SupportCode,
		Article:               local.Article,
		PricelistID:           local.PricelistID,
		WarehousePricelistID:  local.WarehousePricelistID,
		CompetitorPricelistID: local.CompetitorPricelistID,
		ConfigType:            local.ConfigType,
		VendorSpec:            localVendorSpecToModel(local.VendorSpec),
		DisablePriceRefresh:   local.DisablePriceRefresh,
		OnlyInStock:           local.OnlyInStock,
		Line:                  local.Line,
		PriceUpdatedAt:        local.PriceUpdatedAt,
		CreatedAt:             local.CreatedAt,
	}

	if local.ServerID != nil {
		cfg.ID = *local.ServerID
	}
	if local.OriginalUserID != 0 {
		userID := local.OriginalUserID
		cfg.UserID = &userID
	}
	if local.CurrentVersion != nil {
		cfg.CurrentVersionNo = local.CurrentVersion.VersionNo
	}

	return cfg
}

func derefUint(v *uint) uint {
	if v == nil {
		return 0
	}
	return *v
}

func modelVendorSpecToLocal(spec models.VendorSpec) VendorSpec {
	if len(spec) == 0 {
		return nil
	}
	out := make(VendorSpec, 0, len(spec))
	for _, item := range spec {
		row := VendorSpecItem{
			SortOrder:           item.SortOrder,
			VendorPartnumber:    item.VendorPartnumber,
			Quantity:            item.Quantity,
			Description:         item.Description,
			UnitPrice:           item.UnitPrice,
			TotalPrice:          item.TotalPrice,
			ResolvedLotName:     item.ResolvedLotName,
			ResolutionSource:    item.ResolutionSource,
			ManualLotSuggestion: item.ManualLotSuggestion,
			LotQtyPerPN:         item.LotQtyPerPN,
		}
		if len(item.LotAllocations) > 0 {
			row.LotAllocations = make([]VendorSpecLotAllocation, 0, len(item.LotAllocations))
			for _, alloc := range item.LotAllocations {
				row.LotAllocations = append(row.LotAllocations, VendorSpecLotAllocation{
					LotName:  alloc.LotName,
					Quantity: alloc.Quantity,
				})
			}
		}
		if len(item.LotMappings) > 0 {
			row.LotMappings = make([]VendorSpecLotMapping, 0, len(item.LotMappings))
			for _, mapping := range item.LotMappings {
				row.LotMappings = append(row.LotMappings, VendorSpecLotMapping{
					LotName:       mapping.LotName,
					QuantityPerPN: mapping.QuantityPerPN,
				})
			}
		}
		out = append(out, row)
	}
	return out
}

func localVendorSpecToModel(spec VendorSpec) models.VendorSpec {
	if len(spec) == 0 {
		return nil
	}
	out := make(models.VendorSpec, 0, len(spec))
	for _, item := range spec {
		row := models.VendorSpecItem{
			SortOrder:           item.SortOrder,
			VendorPartnumber:    item.VendorPartnumber,
			Quantity:            item.Quantity,
			Description:         item.Description,
			UnitPrice:           item.UnitPrice,
			TotalPrice:          item.TotalPrice,
			ResolvedLotName:     item.ResolvedLotName,
			ResolutionSource:    item.ResolutionSource,
			ManualLotSuggestion: item.ManualLotSuggestion,
			LotQtyPerPN:         item.LotQtyPerPN,
		}
		if len(item.LotAllocations) > 0 {
			row.LotAllocations = make([]models.VendorSpecLotAllocation, 0, len(item.LotAllocations))
			for _, alloc := range item.LotAllocations {
				row.LotAllocations = append(row.LotAllocations, models.VendorSpecLotAllocation{
					LotName:  alloc.LotName,
					Quantity: alloc.Quantity,
				})
			}
		}
		if len(item.LotMappings) > 0 {
			row.LotMappings = make([]models.VendorSpecLotMapping, 0, len(item.LotMappings))
			for _, mapping := range item.LotMappings {
				row.LotMappings = append(row.LotMappings, models.VendorSpecLotMapping{
					LotName:       mapping.LotName,
					QuantityPerPN: mapping.QuantityPerPN,
				})
			}
		}
		out = append(out, row)
	}
	return out
}

func ProjectToLocal(project *models.Project) *LocalProject {
	local := &LocalProject{
		UUID:          project.UUID,
		OwnerUsername: project.OwnerUsername,
		Code:          project.Code,
		Variant:       project.Variant,
		Name:          project.Name,
		TrackerURL:    project.TrackerURL,
		IsActive:      project.IsActive,
		IsSystem:      project.IsSystem,
		CreatedAt:     project.CreatedAt,
		UpdatedAt:     project.UpdatedAt,
		SyncStatus:    "pending",
	}
	if project.ID > 0 {
		serverID := project.ID
		local.ServerID = &serverID
	}
	return local
}

func LocalToProject(local *LocalProject) *models.Project {
	project := &models.Project{
		UUID:          local.UUID,
		OwnerUsername: local.OwnerUsername,
		Code:          local.Code,
		Variant:       local.Variant,
		Name:          local.Name,
		TrackerURL:    local.TrackerURL,
		IsActive:      local.IsActive,
		IsSystem:      local.IsSystem,
		CreatedAt:     local.CreatedAt,
		UpdatedAt:     local.UpdatedAt,
	}
	if local.ServerID != nil {
		project.ID = *local.ServerID
	}
	return project
}

// PricelistToLocal converts models.Pricelist to LocalPricelist
func PricelistToLocal(pl *models.Pricelist) *LocalPricelist {
	name := pl.Notification
	if name == "" {
		name = pl.Version
	}

	return &LocalPricelist{
		ServerID:  pl.ID,
		Source:    pl.Source,
		Version:   pl.Version,
		Name:      name,
		CreatedAt: pl.CreatedAt,
		SyncedAt:  time.Now(),
		IsUsed:    false,
	}
}

// LocalToPricelist converts LocalPricelist to models.Pricelist
func LocalToPricelist(local *LocalPricelist) *models.Pricelist {
	return &models.Pricelist{
		ID:           local.ServerID,
		Source:       local.Source,
		Version:      local.Version,
		Notification: local.Name,
		CreatedAt:    local.CreatedAt,
		IsActive:     true,
	}
}

// PricelistItemToLocal converts models.PricelistItem to LocalPricelistItem
func PricelistItemToLocal(item *models.PricelistItem, localPricelistID uint) *LocalPricelistItem {
	partnumbers := make(LocalStringList, 0, len(item.Partnumbers))
	partnumbers = append(partnumbers, item.Partnumbers...)
	return &LocalPricelistItem{
		PricelistID:  localPricelistID,
		LotName:      item.LotName,
		LotCategory:  item.LotCategory,
		Price:        item.Price,
		AvailableQty: item.AvailableQty,
		Partnumbers:  partnumbers,
	}
}

// LocalToPricelistItem converts LocalPricelistItem to models.PricelistItem
func LocalToPricelistItem(local *LocalPricelistItem, serverPricelistID uint) *models.PricelistItem {
	partnumbers := make([]string, 0, len(local.Partnumbers))
	partnumbers = append(partnumbers, local.Partnumbers...)
	return &models.PricelistItem{
		ID:           local.ID,
		PricelistID:  serverPricelistID,
		LotName:      local.LotName,
		LotCategory:  local.LotCategory,
		Price:        local.Price,
		AvailableQty: local.AvailableQty,
		Partnumbers:  partnumbers,
	}
}

// ComponentToLocal converts models.LotMetadata to LocalComponent
func ComponentToLocal(meta *models.LotMetadata) *LocalComponent {
	var lotDesc string
	var category string

	if meta.Lot != nil {
		lotDesc = meta.Lot.LotDescription
	}

	// Extract category from lot_name (e.g., "CPU_AMD_9654" -> "CPU")
	if len(meta.LotName) > 0 {
		for i, ch := range meta.LotName {
			if ch == '_' {
				category = meta.LotName[:i]
				break
			}
		}
	}

	return &LocalComponent{
		LotName:        meta.LotName,
		LotDescription: lotDesc,
		Category:       category,
		Model:          meta.Model,
	}
}

// LocalToComponent converts LocalComponent to models.LotMetadata
func LocalToComponent(local *LocalComponent) *models.LotMetadata {
	return &models.LotMetadata{
		LotName: local.LotName,
		Model:   local.Model,
		Lot: &models.Lot{
			LotName:        local.LotName,
			LotDescription: local.LotDescription,
		},
	}
}
