package storage

import (
	"fmt"
	"sort"
	"time"

	bolt "go.etcd.io/bbolt"
)

func (s *Storage) CreateCategory(name string, order int) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)

		if b.Get([]byte(name)) != nil {
			return fmt.Errorf("category %q already exists", name)
		}

		cat := Category{
			Name:      name,
			Order:     order,
			CreatedAt: time.Now(),
		}

		data, err := encodeJSON(cat)
		if err != nil {
			return err
		}

		return b.Put([]byte(name), data)
	})
}

func (s *Storage) DeleteCategory(name string) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)
		if b.Get([]byte(name)) == nil {
			return fmt.Errorf("category %q not found", name)
		}
		return b.Delete([]byte(name))
	})
}

func (s *Storage) GetCategory(name string) (*Category, error) {
	var cat *Category
	err := s.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)
		data := b.Get([]byte(name))
		if data == nil {
			return fmt.Errorf("category %q not found", name)
		}
		cat = &Category{}
		return decodeJSON(data, cat)
	})
	return cat, err
}

func (s *Storage) ListCategories() ([]Category, error) {
	var categories []Category
	err := s.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)
		return b.ForEach(func(k, v []byte) error {
			var cat Category
			if err := decodeJSON(v, &cat); err != nil {
				return err
			}
			categories = append(categories, cat)
			return nil
		})
	})
	if err != nil {
		return nil, err
	}

	sort.Slice(categories, func(i, j int) bool {
		if categories[i].Order != categories[j].Order {
			return categories[i].Order < categories[j].Order
		}
		return categories[i].CreatedAt.Before(categories[j].CreatedAt)
	})

	return categories, nil
}

func (s *Storage) UpdateCategoryOrder(name string, order int) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)
		data := b.Get([]byte(name))
		if data == nil {
			return fmt.Errorf("category %q not found", name)
		}

		var cat Category
		if err := decodeJSON(data, &cat); err != nil {
			return err
		}

		cat.Order = order
		newData, err := encodeJSON(cat)
		if err != nil {
			return err
		}

		return b.Put([]byte(name), newData)
	})
}

func (s *Storage) RenameCategory(oldName, newName string) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)

		// 检查旧分类是否存在
		data := b.Get([]byte(oldName))
		if data == nil {
			return fmt.Errorf("category %q not found", oldName)
		}

		// 检查新名称是否已存在
		if b.Get([]byte(newName)) != nil {
			return fmt.Errorf("category %q already exists", newName)
		}

		// 解码旧分类
		var cat Category
		if err := decodeJSON(data, &cat); err != nil {
			return err
		}

		// 更新名称
		cat.Name = newName
		newData, err := encodeJSON(cat)
		if err != nil {
			return err
		}

		// 删除旧键，写入新键
		if err := b.Delete([]byte(oldName)); err != nil {
			return err
		}
		if err := b.Put([]byte(newName), newData); err != nil {
			return err
		}

		// 同步更新所有条目的分类名
		entries := tx.Bucket(bucketEntries)
		return entries.ForEach(func(k, v []byte) error {
			var entry Entry
			if err := decodeJSON(v, &entry); err != nil {
				return err
			}
			if entry.Category == oldName {
				entry.Category = newName
				newEntryData, err := encodeJSON(entry)
				if err != nil {
					return err
				}
				return entries.Put(k, newEntryData)
			}
			return nil
		})
	})
}

func (s *Storage) CategoryExists(name string) bool {
	exists := false
	s.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket(bucketCategories)
		exists = b.Get([]byte(name)) != nil
		return nil
	})
	return exists
}
