// kotlin_api.go — Kotlin 友好 API 封装层
//
// 本文件补充 bridge.go 中未暴露的 SDK 能力，并提供 Identity 管理接口。
// 与 bridge.go 保持相同的 gomobile 导出约定：
//   - 返回 string：空字符串=成功，非空=错误信息
//   - 返回 JSON string：查询结果以 JSON 编码
//
// 设计文档：docs/implementation/99_Go层Kotlin友好化重构.md
// 能力清单：docs/implementation/98_Go层能力封装清单.md
package teamspeak

import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"log"
	"sort"
	"strings"
	"time"

	ts "github.com/honeybbq/teamspeak-go"
	"github.com/honeybbq/teamspeak-go/crypto"
)

// ═══════════════════════════════════════════════════════════════
// 一、Identity 管理
// ═══════════════════════════════════════════════════════════════

// GenerateIdentity 生成一个新的加密身份，返回序列化的字符串。
// Kotlin 侧应将此字符串持久化（SharedPreferences / DataStore），
// 后续连接时通过 ConnectWithIdentity 复用，避免每次生成新身份。
//
// securityLevel: 推荐值 8（2048-bit RSA）。值越大生成越慢。
//
// 返回格式: "base64EncodedPrivateKey:offset"
// 返回空字符串表示生成失败。
func GenerateIdentity(securityLevel int) string {
	identity, err := crypto.GenerateIdentity(securityLevel)
	if err != nil {
		log.Printf("[TSBridge] GenerateIdentity error: %v", err)
		return ""
	}

	return identity.String()
}

// ConnectWithIdentity 使用已有的 identity 连接到 TeamSpeak 服务器。
// identityStr 由 GenerateIdentity 生成并由 Kotlin 侧持久化。
// 其余参数和行为与 Connect 相同。
//
// 返回：空字符串表示连接成功，非空为错误信息。
func (c *TSClient) ConnectWithIdentity(identityStr, host, nickname, password, defaultChannel, defaultChannelPassword string, cb EventCallback) string {
	c.Disconnect()
	c.stopEventQueue()
	c.mu.Lock()
	c.callback = cb
	c.connected = false
	c.host = host
	c.mu.Unlock()

	// 初始化事件队列和 Android decoder，避免旧的对象初始化路径留下 nil factory。
	c.initEventQueue()
	c.ensureReceiveFactory()
	c.StartReceiveAudio()

	identity, err := crypto.IdentityFromString(identityStr)
	if err != nil {
		return fmt.Sprintf("identity 解析失败: %v", err)
	}

	// 计算 TeamSpeak UID（base64(SHA1(publicKey))），用于僵尸会话过滤。
	// 不能直接存储 identity 字符串，因为 UID 是公钥的哈希，格式完全不同。
	uid := crypto.GetUidFromPublicKey(identity.PublicKeyBase64())
	c.mu.Lock()
	c.selfUID = uid
	c.mu.Unlock()

	opts := []ts.ClientOption{}
	if password != "" {
		opts = append(opts, ts.WithServerPassword(password))
	}
	if defaultChannel != "" {
		opts = append(opts, ts.WithDefaultChannel(defaultChannel))
	}
	if defaultChannelPassword != "" {
		opts = append(opts, ts.WithDefaultChannelPassword(defaultChannelPassword))
	}

	client := ts.NewClient(identity, host, nickname, opts...)

	c.mu.Lock()
	c.client = client
	c.mu.Unlock()

	// 注册事件
	c.registerEvents(client)

	if err := client.Connect(); err != nil {
		c.Disconnect()
		return fmt.Sprintf("连接失败: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	if err := client.WaitConnected(ctx); err != nil {
		c.Disconnect()
		return fmt.Sprintf("连接失败: %v", err)
	}

	// 延迟执行僵尸清理：连接刚建立时客户端在默认频道，ListClients 可能尚未
	// 收到服务器发来的完整客户端列表。延迟 3 秒确保所有 notifycliententerview
	// 事件已到达，此时 ListClients 能发现不同频道中的僵尸会话。
	go func() {
		time.Sleep(3 * time.Second)
		if c.isCurrentClient(client) {
			c.cleanupDuplicateIdentitySessions(client, identity)
		}
	}()
	return ""
}

// cleanupDuplicateIdentitySessions removes stale sessions using the same persisted
// identity, while always preserving the newly connected session.
func (c *TSClient) cleanupDuplicateIdentitySessions(client *ts.Client, identity *crypto.Identity) {
	clients, err := client.ListClients()
	if err != nil {
		log.Printf("[TSBridge] duplicate session scan failed: %v", err)
		return
	}
	uid := crypto.GetUidFromPublicKey(identity.PublicKeyBase64())
	currentID := client.ClientID()
	for _, candidate := range clients {
		if candidate.ID == currentID || candidate.UID != uid {
			continue
		}
		if err := client.KickClient(candidate.ID, 5, "Replaced stale mobile session"); err != nil {
			log.Printf("[TSBridge] stale session kick failed clid=%d: %v", candidate.ID, err)
		} else {
			log.Printf("[TSBridge] stale session kicked clid=%d uid=%s", candidate.ID, uid)
		}
	}
}

// ═══════════════════════════════════════════════════════════════
// 二、查询能力（补充 bridge.go 未暴露的方法）
// ═══════════════════════════════════════════════════════════════

// FindChannelsJSON 按名称模式搜索频道。
// 返回 JSON 数组：[{"id":"1","name":"匹配的频道"}, ...]
// 空数组 "[]" 表示无匹配或出错。
func (c *TSClient) FindChannelsJSON(pattern string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "[]"
	}

	channels, err := client.FindChannels(pattern)
	if err != nil {
		log.Printf("[TSBridge] FindChannels error: %v", err)
		return "[]"
	}

	result := make([]channelJSON, len(channels))
	for i, ch := range channels {
		result[i] = channelJSON{
			ID:   fmt.Sprintf("%d", ch.ID),
			Name: ch.Name,
		}
	}

	data, err := json.Marshal(result)
	if err != nil {
		log.Printf("[TSBridge] FindChannels JSON marshal error: %v", err)
		return "[]"
	}
	return string(data)
}

// FindClientByNameJSON 按昵称搜索数据库客户端。
// 返回 JSON 对象：{"uid":"xxx","dbid":"123"}
// 空对象 "{}" 表示无匹配或出错。
func (c *TSClient) FindClientByNameJSON(nickname string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "{}"
	}

	uid, dbid, err := client.FindClientByName(nickname)
	if err != nil {
		log.Printf("[TSBridge] FindClientByName error: %v", err)
		return "{}"
	}

	result := map[string]string{
		"uid":  uid,
		"dbid": fmt.Sprintf("%d", dbid),
	}
	data, err := json.Marshal(result)
	if err != nil {
		return "{}"
	}
	return string(data)
}

// FindClientByDBIDJSON 按数据库 ID 查找客户端 UID。
// 返回 JSON 对象：{"uid":"xxx"}
// 空对象 "{}" 表示无匹配或出错。
func (c *TSClient) FindClientByDBIDJSON(dbidStr string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "{}"
	}

	var dbid uint64
	if _, err := fmt.Sscanf(dbidStr, "%d", &dbid); err != nil {
		return "{}"
	}

	uid, err := client.FindClientByDBID(dbid)
	if err != nil {
		log.Printf("[TSBridge] FindClientByDBID error: %v", err)
		return "{}"
	}

	result := map[string]string{"uid": uid}
	data, err := json.Marshal(result)
	if err != nil {
		return "{}"
	}
	return string(data)
}

// ListChannelsSortedJSON 获取去重+树形排序的详细频道列表。
// 使用 channellist -topic -flags -voice -limits -icon 获取完整数据，
// 按 channel_order 排序，先顶层频道再子频道（树形扁平化）。
// 自动按 ID 去重（保留最后出现的条目）。
// 返回：JSON 数组，字段与 GetChannelsDetailedJSON 一致。
func (c *TSClient) ListChannelsSortedJSON() string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "[]"
	}

	channels, err := client.ListChannelsDetailed()
	if err != nil {
		log.Printf("[KotlinAPI] ListChannelsSorted ListChannelsDetailed error: %v", err)
		return "[]"
	}

	// 去重：按 ID，保留最后出现的
	seen := make(map[uint64]bool)
	deduped := make([]ts.ChannelInfoDetailed, 0, len(channels))
	for _, ch := range channels {
		if seen[ch.ID] {
			continue
		}
		seen[ch.ID] = true
		deduped = append(deduped, ch)
	}

	// 按 ParentID 分组
	children := make(map[uint64][]ts.ChannelInfoDetailed)
	var tops []ts.ChannelInfoDetailed
	for _, ch := range deduped {
		if ch.ParentID == 0 {
			tops = append(tops, ch)
		} else {
			children[ch.ParentID] = append(children[ch.ParentID], ch)
		}
	}

	// 按 Order 排序
	sort.Slice(tops, func(i, j int) bool {
		return tops[i].Order < tops[j].Order
	})
	for _, list := range children {
		sort.Slice(list, func(i, j int) bool {
			return list[i].Order < list[j].Order
		})
	}

	// 树形扁平化：顶层 → 每个频道的子频道紧跟其后
	var sorted []ts.ChannelInfoDetailed
	var flatten func(ch ts.ChannelInfoDetailed)
	flatten = func(ch ts.ChannelInfoDetailed) {
		sorted = append(sorted, ch)
		for _, child := range children[ch.ID] {
			flatten(child)
		}
	}
	for _, ch := range tops {
		flatten(ch)
	}

	// 转换为 JSON
	result := make([]channelDetailedJSON, len(sorted))
	for i, ch := range sorted {
		result[i] = channelDetailedJSON{
			ID:                          fmt.Sprintf("%d", ch.ID),
			ParentID:                    fmt.Sprintf("%d", ch.ParentID),
			Name:                        ch.Name,
			Topic:                       ch.Topic,
			Order:                       fmt.Sprintf("%d", ch.Order),
			Codec:                       ch.Codec,
			CodecQuality:                ch.CodecQuality,
			NeededTalkPower:             ch.NeededTalkPower,
			MaxClients:                  ch.MaxClients,
			MaxFamilyClients:            ch.MaxFamilyClients,
			IsMaxClientsUnlimited:       ch.IsMaxClientsUnlimited,
			IsMaxFamilyClientsUnlimited: ch.IsMaxFamilyClientsUnlimited,
			IsPermanent:                 ch.IsPermanent,
			IsSemiPermanent:             ch.IsSemiPermanent,
			IsDefault:                   ch.IsDefault,
			IsPassword:                  ch.IsPassword,
			IsOrdered:                   ch.IsOrdered,
			IconID:                      fmt.Sprintf("%d", ch.IconID),
			NeededModifyPower:           ch.NeededModifyPower,
		}
	}
	data, err := json.Marshal(result)
	if err != nil {
		return "[]"
	}
	return string(data)
}

// ═══════════════════════════════════════════════════════════════
// 三、操作能力（补充 bridge.go 未暴露的方法）
// ═══════════════════════════════════════════════════════════════

// MoveClient 将指定客户端移动到目标频道。
// clientID: 客户端 ID（clid）
// channelID: 目标频道 ID
// password: 频道密码（可选，无密码传空字符串）
// 返回：空字符串表示成功，非空为错误信息。
func (c *TSClient) MoveClient(clientID int, channelIDStr, password string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "未连接"
	}

	var channelID uint64
	if _, err := fmt.Sscanf(channelIDStr, "%d", &channelID); err != nil {
		return fmt.Sprintf("无效的频道 ID: %v", err)
	}

	if err := client.ClientMove(uint16(clientID), channelID, password); err != nil {
		return fmt.Sprintf("移动失败: %v", err)
	}
	return ""
}

// MoveChannel 移动频道到新的父频道或调整排序。
// channelID: 要移动的频道 ID
// parentID: 新的父频道 ID（0 = 顶层）
// order: 排序位置（0 = 最顶部）
// 返回：空字符串表示成功，非空为错误信息。
func (c *TSClient) MoveChannel(channelIDStr, parentIDStr, orderStr string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "未连接"
	}

	var channelID, parentID, order uint64
	if _, err := fmt.Sscanf(channelIDStr, "%d", &channelID); err != nil {
		return fmt.Sprintf("无效的频道 ID: %v", err)
	}
	if _, err := fmt.Sscanf(parentIDStr, "%d", &parentID); err != nil {
		return fmt.Sprintf("无效的父频道 ID: %v", err)
	}
	if _, err := fmt.Sscanf(orderStr, "%d", &order); err != nil {
		return fmt.Sprintf("无效的排序值: %v", err)
	}

	if err := client.MoveChannel(channelID, parentID, order); err != nil {
		return fmt.Sprintf("移动频道失败: %v", err)
	}
	return ""
}

// DeleteAllBans 清除所有封禁记录。
// 返回：空字符串表示成功，非空为错误信息。
func (c *TSClient) DeleteAllBans() string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "未连接"
	}

	if err := client.DeleteAllBans(); err != nil {
		return fmt.Sprintf("清除失败: %v", err)
	}
	return ""
}

// DeleteComplaint 删除指定投诉。
// targetDBID: 被投诉者的数据库 ID
// fromDBID: 投诉者的数据库 ID
// 返回：空字符串表示成功，非空为错误信息。
func (c *TSClient) DeleteComplaint(targetDBIDStr, fromDBIDStr string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "未连接"
	}

	var targetDBID, fromDBID uint64
	if _, err := fmt.Sscanf(targetDBIDStr, "%d", &targetDBID); err != nil {
		return fmt.Sprintf("无效的目标 DBID: %v", err)
	}
	if _, err := fmt.Sscanf(fromDBIDStr, "%d", &fromDBID); err != nil {
		return fmt.Sprintf("无效的来源 DBID: %v", err)
	}

	if err := client.DeleteComplaint(targetDBID, fromDBID); err != nil {
		return fmt.Sprintf("删除投诉失败: %v", err)
	}
	return ""
}

// ═══════════════════════════════════════════════════════════════
// 四、文件传输（初始化阶段）
// ═══════════════════════════════════════════════════════════════

// fileTransferInitJSON 文件传输初始化结果的 JSON 结构
type fileTransferInitJSON struct {
	Host                 string `json:"host"`
	Port                 uint16 `json:"port"`
	Key                  string `json:"key"`
	Size                 uint64 `json:"size,omitempty"`
	ClientFileTransferID uint16 `json:"clientFileTransferID"`
	ServerFileTransferID uint16 `json:"serverFileTransferID"`
	SeekPosition         uint64 `json:"seekPosition,omitempty"`
}

// FileTransferInitUploadJSON 初始化文件上传。
// channelID: 目标频道 ID
// path: 频道内虚拟路径（如 "/myfile.txt"）
// size: 文件大小（字节）
// overwrite: 是否覆盖已有文件
//
// 返回 JSON：{"port":0,"key":"...","clientFileTransferID":0,"serverFileTransferID":0,"seekPosition":0}
// 空对象 "{}" 表示失败。
//
// 注意：TCP 连接的 host 为当前服务器地址，port 从返回的 JSON 中获取。
func (c *TSClient) FileTransferInitUploadJSON(channelIDStr, path string, size int64, overwrite bool) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "{}"
	}

	var channelID uint64
	if _, err := fmt.Sscanf(channelIDStr, "%d", &channelID); err != nil {
		return "{}"
	}

	info, err := client.FileTransferInitUpload(channelID, path, "", uint64(size), overwrite)
	if err != nil {
		log.Printf("[TSBridge] FileTransferInitUpload error: %v", err)
		return "{}"
	}

	result := fileTransferInitJSON{
		Port:                 info.Port,
		Key:                  info.FileTransferKey,
		ClientFileTransferID: info.ClientFileTransferID,
		ServerFileTransferID: info.ServerFileTransferID,
		SeekPosition:         info.SeekPosition,
	}
	data, err := json.Marshal(result)
	if err != nil {
		return "{}"
	}
	return string(data)
}

// FileTransferInitDownloadJSON 初始化文件下载。
// channelID: 目标频道 ID
// path: 频道内虚拟路径（如 "/myfile.txt"）
//
// 返回 JSON：{"port":0,"key":"...","size":0,"clientFileTransferID":0,"serverFileTransferID":0}
// 空对象 "{}" 表示失败。
func (c *TSClient) FileTransferInitDownloadJSON(channelIDStr, path string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "{}"
	}

	var channelID uint64
	if _, err := fmt.Sscanf(channelIDStr, "%d", &channelID); err != nil {
		return "{}"
	}

	info, err := client.FileTransferInitDownload(channelID, path, "")
	if err != nil {
		log.Printf("[TSBridge] FileTransferInitDownload error: %v", err)
		return "{}"
	}

	result := fileTransferInitJSON{
		Port:                 info.Port,
		Key:                  info.FileTransferKey,
		Size:                 info.Size,
		ClientFileTransferID: info.ClientFileTransferID,
		ServerFileTransferID: info.ServerFileTransferID,
	}
	data, err := json.Marshal(result)
	if err != nil {
		return "{}"
	}
	return string(data)
}

// DeleteFile 删除频道中的文件。
// channelID: 频道 ID
// pathsJSON: 要删除的文件路径 JSON 数组，如 ["/file1.txt","/file2.txt"]
// 返回：空字符串表示成功，非空为错误信息。
func (c *TSClient) DeleteFile(channelIDStr, pathsJSON string) string {
	c.mu.Lock()
	client := c.client
	c.mu.Unlock()

	if client == nil {
		return "未连接"
	}

	var channelID uint64
	if _, err := fmt.Sscanf(channelIDStr, "%d", &channelID); err != nil {
		return fmt.Sprintf("无效的频道 ID: %v", err)
	}

	var paths []string
	if err := json.Unmarshal([]byte(pathsJSON), &paths); err != nil {
		return fmt.Sprintf("路径解析失败: %v", err)
	}

	if err := client.FileTransferDeleteFile(channelID, paths); err != nil {
		return fmt.Sprintf("删除失败: %v", err)
	}
	return ""
}

// ═══════════════════════════════════════════════════════════════
// 4.5 文件下载（完整流程）
// ═══════════════════════════════════════════════════════════════

// DownloadFileBytesJSON 下载频道文件并返回 base64 编码的内容。
//
// 完整流程：ftinitdownload → TCP 连接 → 读取字节 → base64 编码。
// channelID: 频道 ID
// path: 文件虚拟路径（如 "/image.png"）
//
// 返回 JSON：{"data":"base64...","size":12345}
// 空对象 "{}" 表示失败。
func (c *TSClient) DownloadFileBytesJSON(channelIDStr, path string) string {
	c.mu.Lock()
	client := c.client
	host := c.host
	c.mu.Unlock()

	if client == nil || host == "" {
		return "{}"
	}

	var channelID uint64
	if _, err := fmt.Sscanf(channelIDStr, "%d", &channelID); err != nil {
		return "{}"
	}

	// 尝试多种路径格式（MyTS 文件可能存储在特殊目录）
	paths := []string{path}
	if !strings.HasPrefix(path, "/") {
		paths = append(paths, "/"+path)
	}

	for _, p := range paths {
		// 1. 初始化下载
		info, err := client.FileTransferInitDownload(channelID, p, "")
		if err != nil {
			log.Printf("[TSBridge] DownloadFileBytes init error (path=%s): %v", p, err)
			continue
		}

		// 2. TCP 连接 + 下载
		var buf bytes.Buffer
		if err := ts.DownloadFileData(host, info, &buf); err != nil {
			log.Printf("[TSBridge] DownloadFileBytes transfer error (path=%s): %v", p, err)
			continue
		}

		// 3. base64 编码（gomobile 不支持 []byte 返回）
		encoded := base64.StdEncoding.EncodeToString(buf.Bytes())

		result := map[string]interface{}{
			"data": encoded,
			"size": buf.Len(),
		}
		data, err := json.Marshal(result)
		if err != nil {
			return "{}"
		}
		return string(data)
	}

	return "{}"
}

// ═══════════════════════════════════════════════════════════════
// 五、批量查询（首次同步优化）
// ═══════════════════════════════════════════════════════════════

// initialSyncJSON 首次同步结果的 JSON 结构
type initialSyncJSON struct {
	Channels      []channelDetailedJSON `json:"channels"`
	Clients       []clientJSON          `json:"clients"`
	SelfID        int                   `json:"selfId"`
	SelfChannelID string                `json:"selfChannelId"`
	Server        *serverInfoJSON       `json:"server"`
}

// GetInitialSyncJSON 执行首次同步，一次性返回所有初始数据。
// 减少 JNI 调用次数（从 4 次降为 1 次）。
//
// 返回 JSON：
//
//	{
//	  "channels": [...],     // 详细频道列表
//	  "clients": [...],      // 在线客户端列表
//	  "selfId": 1,           // 自身客户端 ID
//	  "selfChannelId": "1",  // 自身所在频道 ID
//	  "server": {...}        // 服务器信息
//	}
//
// 任一子查询失败时对应字段为 null/空，不影响其他字段。
func (c *TSClient) GetInitialSyncJSON() string {
	sync := initialSyncJSON{
		SelfID:        c.GetClientID(),
		SelfChannelID: c.GetChannelID(),
	}

	// 频道列表（详细）
	if data := c.GetChannelsDetailedJSON(); data != "[]" {
		var channels []channelDetailedJSON
		if err := json.Unmarshal([]byte(data), &channels); err == nil {
			sync.Channels = channels
		}
	}

	// 客户端列表
	if data := c.GetClientsJSON(); data != "[]" {
		var clients []clientJSON
		if err := json.Unmarshal([]byte(data), &clients); err == nil {
			sync.Clients = clients
		}
	}

	// 服务器信息
	if data := c.GetServerInfoJSON(); data != "{}" {
		var server serverInfoJSON
		if err := json.Unmarshal([]byte(data), &server); err == nil {
			sync.Server = &server
		}
	}

	data, err := json.Marshal(sync)
	if err != nil {
		log.Printf("[TSBridge] GetInitialSyncJSON marshal error: %v", err)
		return "{}"
	}
	return string(data)
}
