package sprite

import (
	"image"
	"image/draw"
	"image/png"
	"log"
	"os"
	"sort"
)

// 设置为true启用调试日志
var debugLog = false

func logDebug(format string, args ...interface{}) {
	if debugLog {
		log.Printf(format, args...)
	}
}

// SpriteIndexNode 表示同一个Index下的精灵链表节点
type SpriteIndexNode struct {
	Sprite *Sprite
	Next   *SpriteIndexNode // 指向同一Index下的下一个精灵
}

// IndexGroup 表示一个索引组，包含所有具有相同Index的精灵
type IndexGroup struct {
	Index int
	Head  *SpriteIndexNode // 指向第一个精灵
	Count int              // 该组中精灵数量
	Next  *IndexGroup      // 指向下一个索引组
	Prev  *IndexGroup      // 指向上一个索引组
}

// NamedSpriteBoard 提供按名称哈希查找，按索引排序的精灵图管理
type NamedSpriteBoard struct {
	Sprites []*Sprite
	// nameMap 用于O(1)的按名称查找，键为Name，值为精灵指针
	nameMap map[string]*Sprite
	// indexGroups 按Index排序的索引组链表
	indexHead *IndexGroup // 索引组链表头
	indexTail *IndexGroup // 索引组链表尾
	// 索引组的映射表，用于O(1)按索引查找索引组
	indexMap map[int]*IndexGroup
	// 总精灵数量
	count int
}

// NewNamedSpriteBoard 创建一个新的NamedSpriteBoard
func NewNamedSpriteBoard() *NamedSpriteBoard {
	return &NamedSpriteBoard{
		Sprites:   make([]*Sprite, 0),
		nameMap:   make(map[string]*Sprite),
		indexMap:  make(map[int]*IndexGroup),
		indexHead: nil,
		indexTail: nil,
		count:     0,
	}
}

// AddSprite 添加精灵，O(1)时间复杂度查找，O(logn)插入
func (b *NamedSpriteBoard) AddSprite(sprite *Sprite) {
	// 必须有名称
	if sprite.Name == "" {
		return
	}

	// 如果已存在同名精灵，先移除
	if _, exists := b.nameMap[sprite.Name]; exists {
		b.RemoveSpriteByName(sprite.Name)
	}

	// 将精灵添加到名称映射
	b.nameMap[sprite.Name] = sprite

	// 查找或创建索引组
	indexGroup, exists := b.indexMap[sprite.Index]
	if !exists {
		// 创建新的索引组
		indexGroup = &IndexGroup{
			Index: sprite.Index,
			Head:  nil,
			Count: 0,
			Next:  nil,
			Prev:  nil,
		}

		// 将索引组添加到映射表
		b.indexMap[sprite.Index] = indexGroup

		// 插入到索引组链表中的正确位置
		b.insertIndexGroup(indexGroup)
	}

	// 创建新的精灵节点
	newNode := &SpriteIndexNode{
		Sprite: sprite,
		Next:   nil,
	}

	// 在索引组中按名称排序插入
	b.insertSpriteToGroup(indexGroup, newNode)

	// 更新计数
	indexGroup.Count++
	b.count++

	// 更新兼容层
	b.updateSpriteArray()
}

// insertIndexGroup 将索引组插入到正确的位置，O(logn)时间复杂度
func (b *NamedSpriteBoard) insertIndexGroup(group *IndexGroup) {
	// 如果是第一个索引组
	if b.indexHead == nil {
		b.indexHead = group
		b.indexTail = group
		return
	}

	// 如果应该插入到头部
	if group.Index < b.indexHead.Index {
		group.Next = b.indexHead
		b.indexHead.Prev = group
		b.indexHead = group
		return
	}

	// 如果应该插入到尾部
	if group.Index > b.indexTail.Index {
		group.Prev = b.indexTail
		b.indexTail.Next = group
		b.indexTail = group
		return
	}

	// 找到插入位置 - 将链表的元素放入数组进行二分查找
	groups := make([]*IndexGroup, 0)
	current := b.indexHead
	for current != nil {
		groups = append(groups, current)
		current = current.Next
	}

	// 二分查找插入位置
	insertPos := sort.Search(len(groups), func(i int) bool {
		return groups[i].Index >= group.Index
	})

	// 插入到找到的位置之前
	prevGroup := groups[insertPos-1]
	nextGroup := groups[insertPos]

	group.Next = nextGroup
	group.Prev = prevGroup
	prevGroup.Next = group
	nextGroup.Prev = group
}

// insertSpriteToGroup 将精灵节点按名称排序插入到索引组，O(n)时间复杂度
// 由于同一个Index下的精灵数量通常不多，所以使用简单的插入排序
func (b *NamedSpriteBoard) insertSpriteToGroup(group *IndexGroup, node *SpriteIndexNode) {
	// 如果索引组为空
	if group.Head == nil {
		group.Head = node
		return
	}

	// 如果应该插入到头部
	if node.Sprite.Name < group.Head.Sprite.Name {
		node.Next = group.Head
		group.Head = node
		return
	}

	// 查找插入位置
	current := group.Head
	for current.Next != nil && current.Next.Sprite.Name < node.Sprite.Name {
		current = current.Next
	}

	// 插入节点
	node.Next = current.Next
	current.Next = node
}

// GetSpriteByName 通过名称获取精灵，O(1)时间复杂度
func (b *NamedSpriteBoard) GetSpriteByName(name string) *Sprite {
	sprite, exists := b.nameMap[name]
	if exists {
		return sprite
	}
	return nil
}

// GetSpritesByIndex 获取具有特定索引的所有精灵，O(1)查找 + O(n)收集
func (b *NamedSpriteBoard) GetSpritesByIndex(index int) []*Sprite {
	group, exists := b.indexMap[index]
	if !exists {
		return nil
	}

	sprites := make([]*Sprite, 0, group.Count)
	current := group.Head
	for current != nil {
		sprites = append(sprites, current.Sprite)
		current = current.Next
	}

	return sprites
}

// RemoveSpriteByName 通过名称删除精灵，O(1)查找 + O(n)删除
func (b *NamedSpriteBoard) RemoveSpriteByName(name string) bool {
	sprite, exists := b.nameMap[name]
	if !exists {
		return false
	}

	// 从名称映射中移除
	delete(b.nameMap, name)

	// 查找对应的索引组
	group := b.indexMap[sprite.Index]
	if group == nil {
		return false
	}

	// 从索引组中移除精灵
	removed := b.removeSpriteFromGroup(group, name)
	if !removed {
		return false
	}

	// 如果索引组变为空，则删除该索引组
	if group.Count == 0 {
		b.removeIndexGroup(group)
	}

	// 更新计数
	b.count--

	// 更新兼容层
	b.updateSpriteArray()

	return true
}

// removeSpriteFromGroup 从索引组中移除指定名称的精灵，O(n)时间复杂度
func (b *NamedSpriteBoard) removeSpriteFromGroup(group *IndexGroup, name string) bool {
	logDebug("removeSpriteFromGroup: 尝试从索引组 %d 中移除精灵 %s", group.Index, name)

	// 如果索引组为空
	if group.Head == nil {
		logDebug("removeSpriteFromGroup: 索引组为空")
		return false
	}

	// 如果是头节点
	if group.Head.Sprite.Name == name {
		logDebug("removeSpriteFromGroup: 移除头节点 %s", name)
		group.Head = group.Head.Next
		group.Count--
		return true
	}

	// 查找节点
	current := group.Head
	for current.Next != nil && current.Next.Sprite.Name != name {
		logDebug("removeSpriteFromGroup: 检查节点 %s", current.Next.Sprite.Name)
		current = current.Next
	}

	// 如果找到了节点
	if current.Next != nil {
		logDebug("removeSpriteFromGroup: 找到并移除节点 %s", name)
		current.Next = current.Next.Next
		group.Count--
		return true
	}

	logDebug("removeSpriteFromGroup: 未找到节点 %s", name)
	return false
}

// removeIndexGroup 从索引组链表中移除索引组，O(1)时间复杂度
func (b *NamedSpriteBoard) removeIndexGroup(group *IndexGroup) {
	// 从索引映射表中移除
	delete(b.indexMap, group.Index)

	// 从链表中移除
	if group.Prev != nil {
		group.Prev.Next = group.Next
	} else {
		b.indexHead = group.Next // 头节点变更
	}

	if group.Next != nil {
		group.Next.Prev = group.Prev
	} else {
		b.indexTail = group.Prev // 尾节点变更
	}
}

// UpdateSpriteIndex 更新精灵的索引，O(1)查找 + O(logn)插入
func (b *NamedSpriteBoard) UpdateSpriteIndex(name string, newIndex int) bool {
	sprite, exists := b.nameMap[name]
	if !exists {
		return false
	}

	// 保存旧索引
	oldIndex := sprite.Index

	// 从旧索引组中移除
	oldGroup := b.indexMap[oldIndex]
	if oldGroup == nil {
		return false
	}

	if !b.removeSpriteFromGroup(oldGroup, name) {
		return false
	}

	// 如果旧索引组变为空，则删除
	if oldGroup.Count == 0 {
		b.removeIndexGroup(oldGroup)
	}

	// 更新精灵的索引
	sprite.Index = newIndex

	// 查找或创建新索引组
	newGroup, exists := b.indexMap[newIndex]
	if !exists {
		// 创建新的索引组
		newGroup = &IndexGroup{
			Index: newIndex,
			Head:  nil,
			Count: 0,
			Next:  nil,
			Prev:  nil,
		}

		// 将索引组添加到映射表
		b.indexMap[newIndex] = newGroup

		// 插入到索引组链表中的正确位置
		b.insertIndexGroup(newGroup)
	}

	// 创建新的精灵节点
	newNode := &SpriteIndexNode{
		Sprite: sprite,
		Next:   nil,
	}

	// 在新索引组中按名称排序插入
	b.insertSpriteToGroup(newGroup, newNode)
	newGroup.Count++

	// 更新兼容层
	b.updateSpriteArray()

	return true
}

// UpdateSpriteName 更新精灵的名称，O(1)查找 + O(n)插入
func (b *NamedSpriteBoard) UpdateSpriteName(oldName, newName string) bool {
	logDebug("UpdateSpriteName: 尝试将 %s 更新为 %s", oldName, newName)
	sprite, exists := b.nameMap[oldName]
	if !exists {
		logDebug("UpdateSpriteName: 未找到精灵 %s", oldName)
		return false
	}

	// 检查新名称是否已存在
	if _, exists := b.nameMap[newName]; exists && newName != oldName {
		logDebug("UpdateSpriteName: 新名称 %s 已存在", newName)
		return false
	}

	// 保存索引
	index := sprite.Index
	logDebug("UpdateSpriteName: 精灵索引为 %d", index)

	// 从索引组中移除再添加，以保持排序
	group := b.indexMap[index]
	if group == nil {
		logDebug("UpdateSpriteName: 未找到索引组 %d", index)
		return false
	}

	logDebug("UpdateSpriteName: 在索引组 %d 中查找名称 %s", index, oldName)
	// 调试输出当前索引组的所有精灵
	current := group.Head
	i := 0
	for current != nil {
		logDebug("UpdateSpriteName: 索引组精灵[%d]: %s", i, current.Sprite.Name)
		current = current.Next
		i++
	}

	// 从索引组链表中删除节点
	if !b.removeSpriteFromGroup(group, oldName) {
		logDebug("UpdateSpriteName: 从索引组中移除精灵 %s 失败", oldName)
		return false
	}

	// 从名称映射中移除旧名称
	delete(b.nameMap, oldName)

	// 更新精灵名称
	sprite.Name = newName

	// 添加到新名称映射
	b.nameMap[newName] = sprite

	// 创建新节点并添加回索引组
	newNode := &SpriteIndexNode{
		Sprite: sprite,
		Next:   nil,
	}
	b.insertSpriteToGroup(group, newNode)
	group.Count++ // 增加计数，因为removeSpriteFromGroup已经减少了计数

	// 更新兼容层
	b.updateSpriteArray()
	logDebug("UpdateSpriteName: 成功更新名称从 %s 到 %s", oldName, newName)

	return true
}

// GetAllSprites 获取所有精灵，按Index主排序，Name次排序
func (b *NamedSpriteBoard) GetAllSprites() []*Sprite {
	sprites := make([]*Sprite, 0, b.count)

	// 遍历所有索引组
	currentGroup := b.indexHead
	for currentGroup != nil {
		// 遍历当前索引组中的所有精灵
		currentNode := currentGroup.Head
		for currentNode != nil {
			sprites = append(sprites, currentNode.Sprite)
			currentNode = currentNode.Next
		}
		currentGroup = currentGroup.Next
	}

	return sprites
}

// updateSpriteArray 更新BaseBoard中的Sprites数组以保持兼容性
func (b *NamedSpriteBoard) updateSpriteArray() {
	b.Sprites = b.GetAllSprites()
}

// RenderToImage 将精灵板渲染为图像
func (b *NamedSpriteBoard) RenderToImage() *image.RGBA {
	// 计算所有精灵图覆盖的最大区域
	var minX, minY, maxX, maxY int

	// 初始化为最大/最小可能值，以便于后续比较
	initialized := false

	// 遍历所有精灵计算边界
	currentGroup := b.indexHead
	for currentGroup != nil {
		currentNode := currentGroup.Head
		for currentNode != nil {
			sprite := currentNode.Sprite
			if sprite.Image != nil {
				srcBounds := sprite.Image.Bounds()
				spriteMinX := sprite.Position.X
				spriteMinY := sprite.Position.Y
				spriteMaxX := sprite.Position.X + srcBounds.Dx()
				spriteMaxY := sprite.Position.Y + srcBounds.Dy()

				// 首次初始化边界值或更新边界
				if !initialized {
					minX, minY = spriteMinX, spriteMinY
					maxX, maxY = spriteMaxX, spriteMaxY
					initialized = true
				} else {
					// 更新边界值
					if spriteMinX < minX {
						minX = spriteMinX
					}
					if spriteMinY < minY {
						minY = spriteMinY
					}
					if spriteMaxX > maxX {
						maxX = spriteMaxX
					}
					if spriteMaxY > maxY {
						maxY = spriteMaxY
					}
				}
			}
			currentNode = currentNode.Next
		}
		currentGroup = currentGroup.Next
	}

	// 如果没有精灵图，则使用默认大小
	if !initialized {
		minX, minY = 0, 0
		maxX, maxY = 1, 1
	}

	// 确保有最小尺寸
	if maxX <= minX {
		maxX = minX + 1
	}
	if maxY <= minY {
		maxY = minY + 1
	}

	// 计算画布尺寸，保留负坐标空间
	width := maxX - minX
	height := maxY - minY

	// 创建画布，大小由精灵图决定
	img := image.NewRGBA(image.Rect(0, 0, width, height))

	// 按索引排序遍历所有精灵组
	currentGroup = b.indexHead
	for currentGroup != nil {
		currentNode := currentGroup.Head
		for currentNode != nil {
			sprite := currentNode.Sprite
			if sprite.Image != nil {
				// 获取精灵的边界
				srcBounds := sprite.Image.Bounds()

				// 计算原始目标区域（相对于minX, minY偏移）
				dstMinX := sprite.Position.X - minX
				dstMinY := sprite.Position.Y - minY
				dstMaxX := dstMinX + srcBounds.Dx()
				dstMaxY := dstMinY + srcBounds.Dy()

				// 计算源图像的裁剪区域（如果精灵部分在画布外）
				srcMinX := srcBounds.Min.X
				srcMinY := srcBounds.Min.Y

				// 处理左边界超出
				if dstMinX < 0 {
					srcMinX -= dstMinX // 向右移动源图像起点
					dstMinX = 0
				}

				// 处理上边界超出
				if dstMinY < 0 {
					srcMinY -= dstMinY // 向下移动源图像起点
					dstMinY = 0
				}

				// 处理右边界超出
				if dstMaxX > width {
					dstMaxX = width
				}

				// 处理下边界超出
				if dstMaxY > height {
					dstMaxY = height
				}

				// 如果裁剪后的区域有效（宽度和高度都大于0）
				if dstMinX < dstMaxX && dstMinY < dstMaxY {
					dstRect := image.Rect(dstMinX, dstMinY, dstMaxX, dstMaxY)
					srcPt := image.Point{X: srcMinX, Y: srcMinY}

					// 绘制裁剪后的精灵到画布上
					draw.Draw(img, dstRect, sprite.Image, srcPt, draw.Over)
				}
			}

			// 移动到下一个精灵
			currentNode = currentNode.Next
		}

		// 移动到下一个索引组
		currentGroup = currentGroup.Next
	}

	return img
}

// SaveToPng 将精灵板渲染为图像并保存到文件
func (b *NamedSpriteBoard) SaveToPng(filename string) error {
	// 渲染图像
	img := b.RenderToImage()

	// 创建文件
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	// 将图像编码为PNG并写入文件
	if err := png.Encode(f, img); err != nil {
		return err
	}

	return nil
}
