using BookmarkApi.Core.Interfaces;
using BookmarkApi.Data.Entities;
using BookmarkApi.Shared.DTOs;
using BookmarkApi.Shared.Enums;

namespace BookmarkApi.Core.Services;

/// <summary>
/// 标签服务实现
/// </summary>
public class TagService : ITagService
{
    private readonly IFreeSql _freeSql;

    public TagService(IFreeSql freeSql)
    {
        _freeSql = freeSql;
    }

    /// <inheritdoc />
    public async Task<List<TagDto>> GetUserTagsAsync(Guid userId, Guid deviceId, bool isAdminDevice)
    {
        var query = _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId);

        // 如果不是管理员设备，需要过滤可见性
        if (!isAdminDevice)
        {
            query = query.Where(b =>
                b.Visibility == VisibilityType.Public ||
                (b.Visibility == VisibilityType.Specified && b.AllowedDevices != null && b.AllowedDevices.Contains(deviceId))
            );
        }

        var bookmarks = await query.ToListAsync();

        // 统计标签使用数量
        var tagCounts = new Dictionary<string, int>();

        foreach (var bookmark in bookmarks)
        {
            foreach (var tag in bookmark.Tags)
            {
                if (tagCounts.ContainsKey(tag))
                {
                    tagCounts[tag]++;
                }
                else
                {
                    tagCounts[tag] = 1;
                }
            }
        }

        return tagCounts
            .Select(kv => new TagDto { Name = kv.Key, Count = kv.Value })
            .OrderByDescending(t => t.Count)
            .ToList();
    }

    /// <inheritdoc />
    public async Task<bool> RenameTagAsync(Guid userId, string oldName, string newName)
    {
        // 获取包含旧标签的所有书签
        var bookmarks = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId && b.Tags.Contains(oldName))
            .ToListAsync();

        if (bookmarks.Count == 0)
        {
            return false;
        }

        foreach (var bookmark in bookmarks)
        {
            var tags = bookmark.Tags.ToList();
            var index = tags.IndexOf(oldName);
            if (index >= 0)
            {
                tags[index] = newName;
                // 去重
                tags = tags.Distinct().ToList();
            }

            await _freeSql.Update<Bookmark>()
                .Set(b => b.Tags, tags.ToArray())
                .Set(b => b.UpdatedAt, DateTime.UtcNow)
                .Where(b => b.Id == bookmark.Id)
                .ExecuteAffrowsAsync();
        }

        return true;
    }

    /// <inheritdoc />
    public async Task<int> DeleteTagAsync(Guid userId, string tagName)
    {
        // 获取包含该标签的所有书签
        var bookmarks = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId && b.Tags.Contains(tagName))
            .ToListAsync();

        var affectedCount = 0;

        foreach (var bookmark in bookmarks)
        {
            var tags = bookmark.Tags.Where(t => t != tagName).ToArray();

            await _freeSql.Update<Bookmark>()
                .Set(b => b.Tags, tags)
                .Set(b => b.UpdatedAt, DateTime.UtcNow)
                .Where(b => b.Id == bookmark.Id)
                .ExecuteAffrowsAsync();

            affectedCount++;
        }

        return affectedCount;
    }

    /// <inheritdoc />
    public async Task<int> MergeTagsAsync(Guid userId, string[] sourceNames, string targetName)
    {
        // 获取包含任意源标签的所有书签
        var bookmarks = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId)
            .ToListAsync();

        var affectedCount = 0;

        foreach (var bookmark in bookmarks)
        {
            var hasSourceTag = bookmark.Tags.Any(t => sourceNames.Contains(t));
            if (!hasSourceTag)
            {
                continue;
            }

            // 移除源标签，添加目标标签
            var tags = bookmark.Tags
                .Where(t => !sourceNames.Contains(t))
                .Append(targetName)
                .Distinct()
                .ToArray();

            await _freeSql.Update<Bookmark>()
                .Set(b => b.Tags, tags)
                .Set(b => b.UpdatedAt, DateTime.UtcNow)
                .Where(b => b.Id == bookmark.Id)
                .ExecuteAffrowsAsync();

            affectedCount++;
        }

        return affectedCount;
    }
}

