package kfa

import (
	"encoding/json"
	"strconv"
	"strings"
	"time"
)

func MapKfaDetailToEntity(detail KfaDetailResult) (*KfaProduct, []KfaProductActiveIngredient, []KfaProductPackaging) {
	now := time.Now()

	var displayName *string
	// Attempt to extract display_name safely if product template exists
	templateB := toJsonb(detail.ProductTemplate)
	if templateB != nil {
		var tpl struct {
			DisplayName string `json:"display_name"`
		}
		if err := json.Unmarshal(templateB, &tpl); err == nil && tpl.DisplayName != "" {
			displayName = &tpl.DisplayName
		}
	}
	if displayName == nil {
		displayName = &detail.Name
	}

	product := &KfaProduct{
		KfaCode:             detail.KfaCode,
		Name:                detail.Name,
		DisplayName:         displayName,
		TradeName:           detail.NamaDagang,
		State:               detail.State,
		IsGeneric:           detail.Generik,
		DosageForm:          toJsonb(detail.DosageForm),
		FarmalkesType:       toJsonb(detail.FarmalkesType),
		Route:               toJsonb(detail.RutePemberian),
		ControlledDrug:      toJsonb(detail.ControlledDrug),
		Uom:                 toJsonb(detail.Uom),
		FixPrice:            detail.FixPrice,
		HetPrice:            detail.HetPrice,
		DosePerUnit:         detail.DosePerUnit,
		NetWeight:           detail.NetWeight,
		NetWeightUom:        detail.NetWeightUomName,
		Volume:              detail.Volume,
		VolumeUom:           detail.VolumeUomName,
		ScoreTkdn:           detail.ScoreTkdn,
		ScoreTkdnBmp:        detail.ScoreTkdnBmp,
		ScoreBmp:            detail.ScoreBmp,
		Rxterm:              detail.Rxterm,
		Manufacturer:        detail.Manufacturer,
		Registrar:           detail.Registrar,
		Nie:                 detail.Nie,
		Hscode:              detail.FarmalkesHscode,
		LkppCode:            detail.KodeLkpp,
		IsLkppActive:        detail.TayangLkpp,
		Description:         detail.Description,
		Indication:          detail.Indication,
		SideEffect:          detail.SideEffect,
		Warning:             detail.Warning,
		Image:               detail.Image,
		DrugClassification:  detail.KlasifikasiIzin,
		ManufacturingOrigin: detail.ProduksiBuatan,
		AtcInfo:             buildAtcInfo(detail),
		Fornas:              toJsonb(detail.Fornas),
		DosageUsage:         toJsonb(detail.DosageUsage),
		Tags:                toJsonb(detail.Tags),
		IdentifierIds:       toJsonb(detail.IdentifierIds),
		ProductTemplate:     templateB,
		Replacement:         toJsonb(detail.Replacement),
		Ucum:                toJsonb(detail.Ucum),
		CreatedAt:           now,
		UpdatedAt:           parseTime(detail.UpdatedAt, now),
		Active:              &detail.Active,
	}

	var ingredients []KfaProductActiveIngredient
	for _, ing := range detail.ActiveIngredients {
		val, unit := parseStrength(ing.KekuatanZatAktif)
		ingredients = append(ingredients, KfaProductActiveIngredient{
			ProductKfaCode: product.KfaCode,
			ProductDisplay: product.Name,
			SubstanceCode:  ing.KfaCode,
			SubstanceName:  ing.ZatAktif,
			StrengthValue:  val,
			StrengthUnit:   unit,
			StrengthText:   ing.KekuatanZatAktif,
			State:          ing.State,
			CreatedAt:      now,
			UpdatedAt:      parseTime(ing.UpdatedAt, now),
			Active:         &ing.Active,
		})
	}

	var packagings []KfaProductPackaging
	for _, pkg := range detail.PackagingIds {
		active := true
		packagings = append(packagings, KfaProductPackaging{
			ProductKfaCode: product.KfaCode,
			ProductDisplay: product.Name,
			Code:           pkg.KfaCode,
			Name:           pkg.Name,
			Quantity:       pkg.Qty,
			Unit:           pkg.UomId,
			Price:          pkg.PackPrice,
			State:          "valid",
			CreatedAt:      now,
			UpdatedAt:      now,
			Active:         &active,
		})
	}

	return product, ingredients, packagings
}

func toJsonb(v interface{}) json.RawMessage {
	if v == nil {
		return nil
	}
	b, err := json.Marshal(v)
	if err != nil || string(b) == "null" {
		return nil
	}
	return b
}

func buildAtcInfo(d KfaDetailResult) json.RawMessage {
	m := map[string]interface{}{
		"atc_ddd": d.AtcDdd,
		"atc_l1":  d.AtcL1,
		"atc_l2":  d.AtcL2,
		"atc_l3":  d.AtcL3,
		"atc_l4":  d.AtcL4,
		"atc_l5":  d.AtcL5,
	}
	return toJsonb(m)
}

func parseStrength(text string) (*float64, string) {
	text = strings.TrimSpace(text)
	if text == "" {
		return nil, ""
	}
	parts := strings.Split(text, " ")
	if len(parts) == 0 {
		return nil, ""
	}
	val, err := strconv.ParseFloat(parts[0], 64)
	if err != nil {
		return nil, text
	}
	var unit string
	if len(parts) > 1 {
		unit = strings.Join(parts[1:], " ")
	}
	return &val, unit
}

func parseTime(t *string, defaultTime time.Time) time.Time {
	if t == nil || *t == "" {
		return defaultTime
	}
	parsed, err := time.Parse("2006-01-02 15:04:05", *t)
	if err != nil {
		return defaultTime
	}
	return parsed
}
