package empyrionitems

// Loot group parser for Empyrion's `LootGroups.ecf`.
// Format:
//
//   { +LootGroup Name: EscapePodEasy
//     Count: all
//     Item_0: EmergencyRations, param1: 1
//     Item_1: WaterBottle, param1: 5
//     ...
//   }
//
// param1 = count (or "low-high" range), param2 = optional probability.
// Item names are canonical Item.Name tokens.

import (
	"bufio"
	"io"
	"os"
	"strings"
)

type LootEntry struct {
	Item        string `json:"item"`
	Count       string `json:"count,omitempty"`
	Probability string `json:"probability,omitempty"`
}

type LootGroup struct {
	Name  string      `json:"name"`
	Count string      `json:"count,omitempty"`
	Items []LootEntry `json:"items"`
}

type LootIndex struct {
	Groups   []LootGroup
	byName   map[string]*LootGroup
	byItem   map[string][]string // ingredientLower → group names
}

func LoadLootFromFile(path string) (*LootIndex, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return LoadLootFromReader(f)
}

func LoadLootFromReader(r io.Reader) (*LootIndex, error) {
	idx := &LootIndex{byName: map[string]*LootGroup{}, byItem: map[string][]string{}}
	sc := bufio.NewScanner(r)
	sc.Buffer(make([]byte, 1024*1024), 1024*1024)

	var current *LootGroup
	var depth int

	for sc.Scan() {
		line := stripComment(sc.Text())
		trim := strings.TrimSpace(line)
		if trim == "" {
			continue
		}

		if current == nil {
			if strings.HasPrefix(trim, "{ +LootGroup ") || strings.HasPrefix(trim, "{+LootGroup ") || strings.HasPrefix(trim, "{ LootGroup ") {
				body := strings.TrimPrefix(trim, "{ +LootGroup ")
				body = strings.TrimPrefix(body, "{+LootGroup ")
				body = strings.TrimPrefix(body, "{ LootGroup ")
				current = &LootGroup{}
				for _, kv := range splitTopLevel(body, ',') {
					parts := strings.SplitN(strings.TrimSpace(kv), ":", 2)
					if len(parts) != 2 {
						continue
					}
					k := strings.TrimSpace(parts[0])
					v := stripQuotes(strings.TrimSpace(parts[1]))
					if strings.EqualFold(k, "name") {
						current.Name = v
					}
				}
				depth = 1
			}
			continue
		}

		opens := strings.Count(trim, "{")
		closes := strings.Count(trim, "}")
		depth += opens - closes
		if depth <= 0 {
			if current.Name != "" {
				cp := *current
				idx.Groups = append(idx.Groups, cp)
				gp := &idx.Groups[len(idx.Groups)-1]
				idx.byName[strings.ToLower(cp.Name)] = gp
				for _, it := range cp.Items {
					low := strings.ToLower(it.Item)
					idx.byItem[low] = append(idx.byItem[low], cp.Name)
				}
			}
			current = nil
			depth = 0
			continue
		}

		parts := strings.SplitN(trim, ":", 2)
		if len(parts) != 2 {
			continue
		}
		key := strings.TrimSpace(parts[0])
		val := stripComment(strings.TrimSpace(parts[1]))

		if strings.HasPrefix(strings.ToLower(key), "item_") {
			// Item_N: Name, param1: count, param2: probability
			le := LootEntry{}
			pieces := splitTopLevel(val, ',')
			for i, p := range pieces {
				p = strings.TrimSpace(p)
				if i == 0 {
					le.Item = stripQuotes(p)
					continue
				}
				kv := strings.SplitN(p, ":", 2)
				if len(kv) != 2 {
					continue
				}
				kk := strings.ToLower(strings.TrimSpace(kv[0]))
				vv := strings.TrimSpace(kv[1])
				switch kk {
				case "param1", "param":
					le.Count = vv
				case "param2", "xdata":
					le.Probability = vv
				}
			}
			if le.Item != "" {
				current.Items = append(current.Items, le)
			}
		} else if strings.EqualFold(key, "Count") {
			current.Count = strings.TrimSpace(val)
		}
	}
	if err := sc.Err(); err != nil {
		return nil, err
	}
	return idx, nil
}

func (idx *LootIndex) ByName(name string) *LootGroup {
	if g, ok := idx.byName[strings.ToLower(name)]; ok {
		c := *g
		return &c
	}
	return nil
}

func (idx *LootIndex) DroppedBy(itemName string) []string {
	return append([]string{}, idx.byItem[strings.ToLower(itemName)]...)
}
