package app

import (
	"encoding/json"
	"errors"
	"fmt"

	"git.echol.cn/loser/st/server/global"
	"git.echol.cn/loser/st/server/model/app"
	"git.echol.cn/loser/st/server/model/app/request"
	"git.echol.cn/loser/st/server/model/app/response"
	"go.uber.org/zap"
	"gorm.io/datatypes"
	"gorm.io/gorm"
)

type WorldbookService struct{}

// CreateWorldbook 创建世界书
func (s *WorldbookService) CreateWorldbook(userID uint, req *request.CreateWorldbookRequest) (*response.WorldbookResponse, error) {
	wb := &app.Worldbook{
		UserID:      userID,
		Name:        req.Name,
		Description: req.Description,
		IsPublic:    req.IsPublic,
	}
	if err := global.GVA_DB.Create(wb).Error; err != nil {
		global.GVA_LOG.Error("创建世界书失败", zap.Error(err))
		return nil, err
	}
	resp := response.ToWorldbookResponse(wb)
	return &resp, nil
}

// GetWorldbookList 获取世界书列表（自己的 + 公开的）
func (s *WorldbookService) GetWorldbookList(userID uint, req *request.GetWorldbookListRequest) ([]response.WorldbookResponse, int64, error) {
	var worldbooks []app.Worldbook
	var total int64

	db := global.GVA_DB.Model(&app.Worldbook{}).Where("user_id = ? OR is_public = ?", userID, true)

	if req.Keyword != "" {
		db = db.Where("name LIKE ? OR description LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}

	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	offset := (req.Page - 1) * req.PageSize
	if err := db.Order("updated_at DESC").Offset(offset).Limit(req.PageSize).Find(&worldbooks).Error; err != nil {
		global.GVA_LOG.Error("获取世界书列表失败", zap.Error(err))
		return nil, 0, err
	}

	var list []response.WorldbookResponse
	for i := range worldbooks {
		list = append(list, response.ToWorldbookResponse(&worldbooks[i]))
	}
	return list, total, nil
}

// GetWorldbookByID 获取世界书详情
func (s *WorldbookService) GetWorldbookByID(userID uint, id uint) (*response.WorldbookResponse, error) {
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND (user_id = ? OR is_public = ?)", id, userID, true).
		First(&wb).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("世界书不存在或无权访问")
		}
		return nil, err
	}
	resp := response.ToWorldbookResponse(&wb)
	return &resp, nil
}

// UpdateWorldbook 更新世界书
func (s *WorldbookService) UpdateWorldbook(userID uint, id uint, req *request.UpdateWorldbookRequest) error {
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND user_id = ?", id, userID).First(&wb).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("世界书不存在或无权修改")
		}
		return err
	}

	updates := make(map[string]interface{})
	if req.Name != nil {
		updates["name"] = *req.Name
	}
	if req.Description != nil {
		updates["description"] = *req.Description
	}
	if req.IsPublic != nil {
		updates["is_public"] = *req.IsPublic
	}

	return global.GVA_DB.Model(&wb).Updates(updates).Error
}

// DeleteWorldbook 删除世界书（级联删除条目）
func (s *WorldbookService) DeleteWorldbook(userID uint, id uint) error {
	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
		// 删除所有条目
		if err := tx.Where("worldbook_id = ?", id).Delete(&app.WorldbookEntry{}).Error; err != nil {
			return err
		}
		// 删除世界书
		result := tx.Where("id = ? AND user_id = ?", id, userID).Delete(&app.Worldbook{})
		if result.Error != nil {
			return result.Error
		}
		if result.RowsAffected == 0 {
			return errors.New("世界书不存在或无权删除")
		}
		return nil
	})
}

// CreateEntry 创建世界书条目
func (s *WorldbookService) CreateEntry(userID uint, worldbookID uint, req *request.CreateEntryRequest) (*response.EntryResponse, error) {
	// 验证世界书归属
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND user_id = ?", worldbookID, userID).First(&wb).Error; err != nil {
		return nil, errors.New("世界书不存在或无权操作")
	}

	keysJSON, _ := json.Marshal(req.Keys)
	secKeysJSON, _ := json.Marshal(req.SecondaryKeys)

	enabled := true
	if req.Enabled != nil {
		enabled = *req.Enabled
	}
	probability := req.Probability
	if probability == 0 {
		probability = 100
	}
	order := req.Order
	if order == 0 {
		order = 100
	}
	scanDepth := req.ScanDepth
	if scanDepth == 0 {
		scanDepth = 2
	}

	entry := &app.WorldbookEntry{
		WorldbookID:     worldbookID,
		Comment:         req.Comment,
		Content:         req.Content,
		Keys:            datatypes.JSON(keysJSON),
		SecondaryKeys:   datatypes.JSON(secKeysJSON),
		Constant:        req.Constant,
		Enabled:         enabled,
		UseRegex:        req.UseRegex,
		CaseSensitive:   req.CaseSensitive,
		MatchWholeWords: req.MatchWholeWords,
		Selective:       req.Selective,
		SelectiveLogic:  req.SelectiveLogic,
		Position:        req.Position,
		Depth:           req.Depth,
		Order:           order,
		Probability:     probability,
		ScanDepth:       scanDepth,
		GroupID:         req.GroupID,
	}

	if err := global.GVA_DB.Create(entry).Error; err != nil {
		global.GVA_LOG.Error("创建世界书条目失败", zap.Error(err))
		return nil, err
	}

	// 更新世界书条目计数
	global.GVA_DB.Model(&wb).Update("entry_count", gorm.Expr("entry_count + ?", 1))

	resp := response.ToEntryResponse(entry)
	return &resp, nil
}

// GetEntryList 获取世界书条目列表
func (s *WorldbookService) GetEntryList(userID uint, worldbookID uint) ([]response.EntryResponse, int64, error) {
	// 验证访问权限
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND (user_id = ? OR is_public = ?)", worldbookID, userID, true).
		First(&wb).Error; err != nil {
		return nil, 0, errors.New("世界书不存在或无权访问")
	}

	var entries []app.WorldbookEntry
	var total int64

	db := global.GVA_DB.Model(&app.WorldbookEntry{}).Where("worldbook_id = ?", worldbookID)
	db.Count(&total)

	if err := db.Order("`order` ASC, created_at ASC").Find(&entries).Error; err != nil {
		return nil, 0, err
	}

	var list []response.EntryResponse
	for i := range entries {
		list = append(list, response.ToEntryResponse(&entries[i]))
	}
	return list, total, nil
}

// UpdateEntry 更新世界书条目
func (s *WorldbookService) UpdateEntry(userID uint, entryID uint, req *request.UpdateEntryRequest) error {
	// 查找条目并验证归属
	var entry app.WorldbookEntry
	if err := global.GVA_DB.First(&entry, entryID).Error; err != nil {
		return errors.New("条目不存在")
	}
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND user_id = ?", entry.WorldbookID, userID).First(&wb).Error; err != nil {
		return errors.New("无权修改此条目")
	}

	updates := make(map[string]interface{})
	if req.Comment != nil {
		updates["comment"] = *req.Comment
	}
	if req.Content != nil {
		updates["content"] = *req.Content
	}
	if req.Keys != nil {
		keysJSON, _ := json.Marshal(req.Keys)
		updates["keys"] = datatypes.JSON(keysJSON)
	}
	if req.SecondaryKeys != nil {
		secKeysJSON, _ := json.Marshal(req.SecondaryKeys)
		updates["secondary_keys"] = datatypes.JSON(secKeysJSON)
	}
	if req.Constant != nil {
		updates["constant"] = *req.Constant
	}
	if req.Enabled != nil {
		updates["enabled"] = *req.Enabled
	}
	if req.UseRegex != nil {
		updates["use_regex"] = *req.UseRegex
	}
	if req.CaseSensitive != nil {
		updates["case_sensitive"] = *req.CaseSensitive
	}
	if req.MatchWholeWords != nil {
		updates["match_whole_words"] = *req.MatchWholeWords
	}
	if req.Selective != nil {
		updates["selective"] = *req.Selective
	}
	if req.SelectiveLogic != nil {
		updates["selective_logic"] = *req.SelectiveLogic
	}
	if req.Position != nil {
		updates["position"] = *req.Position
	}
	if req.Depth != nil {
		updates["depth"] = *req.Depth
	}
	if req.Order != nil {
		updates["order"] = *req.Order
	}
	if req.Probability != nil {
		updates["probability"] = *req.Probability
	}
	if req.ScanDepth != nil {
		updates["scan_depth"] = *req.ScanDepth
	}
	if req.GroupID != nil {
		updates["group_id"] = *req.GroupID
	}

	return global.GVA_DB.Model(&entry).Updates(updates).Error
}

// DeleteEntry 删除世界书条目
func (s *WorldbookService) DeleteEntry(userID uint, entryID uint) error {
	var entry app.WorldbookEntry
	if err := global.GVA_DB.First(&entry, entryID).Error; err != nil {
		return errors.New("条目不存在")
	}
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND user_id = ?", entry.WorldbookID, userID).First(&wb).Error; err != nil {
		return errors.New("无权删除此条目")
	}

	if err := global.GVA_DB.Delete(&entry).Error; err != nil {
		return err
	}

	// 更新条目计数
	global.GVA_DB.Model(&wb).Update("entry_count", gorm.Expr("GREATEST(entry_count - 1, 0)"))
	return nil
}

// ImportFromJSON 从 JSON 文件导入世界书（兼容 SillyTavern 格式）
func (s *WorldbookService) ImportFromJSON(userID uint, jsonData []byte, filename string) (*response.WorldbookResponse, error) {
	// 尝试解析 SillyTavern 世界书格式
	var stFormat map[string]interface{}
	if err := json.Unmarshal(jsonData, &stFormat); err != nil {
		return nil, fmt.Errorf("JSON 格式错误: %v", err)
	}

	// 提取世界书名称
	name := filename
	if n, ok := stFormat["name"].(string); ok && n != "" {
		name = n
	}
	description := ""
	if d, ok := stFormat["description"].(string); ok {
		description = d
	}

	wb := &app.Worldbook{
		UserID:      userID,
		Name:        name,
		Description: description,
	}
	if err := global.GVA_DB.Create(wb).Error; err != nil {
		return nil, err
	}

	// 解析条目（SillyTavern entries 格式：map[string]entry 或 []entry）
	var entryCount int
	if entriesRaw, ok := stFormat["entries"]; ok {
		switch entries := entriesRaw.(type) {
		case map[string]interface{}:
			// SillyTavern 格式：键值对
			for _, v := range entries {
				if entryMap, ok := v.(map[string]interface{}); ok {
					s.importEntry(wb.ID, entryMap)
					entryCount++
				}
			}
		case []interface{}:
			// 数组格式
			for _, v := range entries {
				if entryMap, ok := v.(map[string]interface{}); ok {
					s.importEntry(wb.ID, entryMap)
					entryCount++
				}
			}
		}
	}

	// 更新条目计数
	global.GVA_DB.Model(wb).Update("entry_count", entryCount)

	resp := response.ToWorldbookResponse(wb)
	resp.EntryCount = entryCount
	return &resp, nil
}

// importEntry 辅助方法：从 SillyTavern 格式导入单条条目
func (s *WorldbookService) importEntry(worldbookID uint, entryMap map[string]interface{}) {
	content := ""
	if c, ok := entryMap["content"].(string); ok {
		content = c
	}
	if content == "" {
		return
	}

	comment := ""
	if c, ok := entryMap["comment"].(string); ok {
		comment = c
	}

	// 解析 keys（SillyTavern 存为 []string 或 []interface{}）
	var keys []string
	if k, ok := entryMap["key"].([]interface{}); ok {
		for _, kk := range k {
			if ks, ok := kk.(string); ok {
				keys = append(keys, ks)
			}
		}
	} else if k, ok := entryMap["keys"].([]interface{}); ok {
		for _, kk := range k {
			if ks, ok := kk.(string); ok {
				keys = append(keys, ks)
			}
		}
	}
	keysJSON, _ := json.Marshal(keys)

	var secKeys []string
	if k, ok := entryMap["secondary_key"].([]interface{}); ok {
		for _, kk := range k {
			if ks, ok := kk.(string); ok {
				secKeys = append(secKeys, ks)
			}
		}
	} else if k, ok := entryMap["secondaryKeys"].([]interface{}); ok {
		for _, kk := range k {
			if ks, ok := kk.(string); ok {
				secKeys = append(secKeys, ks)
			}
		}
	}
	secKeysJSON, _ := json.Marshal(secKeys)

	constant := false
	if c, ok := entryMap["constant"].(bool); ok {
		constant = c
	}
	enabled := true
	if e, ok := entryMap["enabled"].(bool); ok {
		enabled = e
	} else if d, ok := entryMap["disable"].(bool); ok {
		enabled = !d
	}
	useRegex := false
	if r, ok := entryMap["use_regex"].(bool); ok {
		useRegex = r
	}
	position := 1
	if p, ok := entryMap["position"].(float64); ok {
		position = int(p)
	}
	order := 100
	if o, ok := entryMap["insertion_order"].(float64); ok {
		order = int(o)
	} else if o, ok := entryMap["order"].(float64); ok {
		order = int(o)
	}
	probability := 100
	if p, ok := entryMap["probability"].(float64); ok {
		probability = int(p)
	}

	entry := &app.WorldbookEntry{
		WorldbookID:   worldbookID,
		Comment:       comment,
		Content:       content,
		Keys:          datatypes.JSON(keysJSON),
		SecondaryKeys: datatypes.JSON(secKeysJSON),
		Constant:      constant,
		Enabled:       enabled,
		UseRegex:      useRegex,
		Position:      position,
		Order:         order,
		Probability:   probability,
		ScanDepth:     2,
	}
	global.GVA_DB.Create(entry)
}

// ExportToJSON 导出世界书为 JSON（兼容 SillyTavern 格式）
func (s *WorldbookService) ExportToJSON(userID uint, worldbookID uint) ([]byte, string, error) {
	var wb app.Worldbook
	if err := global.GVA_DB.Where("id = ? AND (user_id = ? OR is_public = ?)", worldbookID, userID, true).
		First(&wb).Error; err != nil {
		return nil, "", errors.New("世界书不存在或无权访问")
	}

	var entries []app.WorldbookEntry
	global.GVA_DB.Where("worldbook_id = ?", worldbookID).Order("`order` ASC").Find(&entries)

	// 构建 SillyTavern 兼容格式
	entriesMap := make(map[string]interface{})
	for i, entry := range entries {
		var keys []string
		json.Unmarshal(entry.Keys, &keys)
		var secKeys []string
		json.Unmarshal(entry.SecondaryKeys, &secKeys)

		entriesMap[fmt.Sprintf("%d", i)] = map[string]interface{}{
			"uid":               entry.ID,
			"key":               keys,
			"secondary_key":     secKeys,
			"comment":           entry.Comment,
			"content":           entry.Content,
			"constant":          entry.Constant,
			"enabled":           entry.Enabled,
			"use_regex":         entry.UseRegex,
			"case_sensitive":    entry.CaseSensitive,
			"match_whole_words": entry.MatchWholeWords,
			"selective":         entry.Selective,
			"selectiveLogic":    entry.SelectiveLogic,
			"position":          entry.Position,
			"depth":             entry.Depth,
			"insertion_order":   entry.Order,
			"probability":       entry.Probability,
			"scanDepth":         entry.ScanDepth,
			"group":             entry.GroupID,
		}
	}

	exportData := map[string]interface{}{
		"name":        wb.Name,
		"description": wb.Description,
		"entries":     entriesMap,
	}

	data, err := json.MarshalIndent(exportData, "", "  ")
	return data, wb.Name + ".json", err
}
