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

namespace BookmarkApi.Core.Services;

/// <summary>
/// 书签服务实现
/// </summary>
public class BookmarkService : IBookmarkService
{
    private readonly IFreeSql _freeSql;

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

    /// <inheritdoc />
    public async Task<List<BookmarkDto>> GetUserBookmarksAsync(Guid userId, Guid deviceId, bool isAdminDevice, string? tag = null, Guid? folderId = null)
    {
        // 查询书签，包含关联数据
        var query = _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId)
            .IncludeMany(b => b.BookmarkTags, then => then.Include(bt => bt.Tag))
            .IncludeMany(b => b.DevicePermissions);

        // 按文件夹筛选
        if (folderId.HasValue)
        {
            query = query.Where(b => b.FolderId == folderId.Value);
        }
        else
        {
            // 默认只查询根目录的书签
            query = query.Where(b => b.FolderId == null);
        }

        var bookmarks = await query
            .OrderByDescending(b => b.Order)
            .ToListAsync();

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

        // 按标签筛选
        if (!string.IsNullOrEmpty(tag))
        {
            bookmarks = bookmarks.Where(b =>
                b.BookmarkTags != null &&
                b.BookmarkTags.Any(bt => bt.Tag != null && bt.Tag.Name == tag)
            ).ToList();
        }

        return bookmarks.Select(MapToDto).ToList();
    }

    /// <inheritdoc />
    public async Task<List<BookmarkDto>> SearchBookmarksAsync(Guid userId, Guid deviceId, bool isAdminDevice, string keyword)
    {
        var lowerKeyword = keyword.ToLower();
        var bookmarks = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId)
            .Where(b =>
                b.Title.ToLower().Contains(lowerKeyword) ||
                b.Url.ToLower().Contains(lowerKeyword) ||
                (b.Description != null && b.Description.ToLower().Contains(lowerKeyword))
            )
            .IncludeMany(b => b.BookmarkTags, then => then.Include(bt => bt.Tag))
            .IncludeMany(b => b.DevicePermissions)
            .OrderByDescending(b => b.VisitCount)
            .OrderByDescending(b => b.Order)
            .ToListAsync();

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

        return bookmarks.Take(20).Select(MapToDto).ToList();
    }

    /// <inheritdoc />
    public async Task<BookmarkDto?> GetBookmarkAsync(Guid bookmarkId, Guid userId, Guid deviceId, bool isAdminDevice)
    {
        var bookmark = await _freeSql.Select<Bookmark>()
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .IncludeMany(b => b.BookmarkTags, then => then.Include(bt => bt.Tag))
            .IncludeMany(b => b.DevicePermissions)
            .FirstAsync();

        if (bookmark == null)
        {
            return null;
        }

        // 检查可见性
        if (!isAdminDevice)
        {
            if (bookmark.Visibility == VisibilityType.Private)
            {
                return null;
            }

            if (bookmark.Visibility == VisibilityType.Specified &&
                (bookmark.DevicePermissions == null || !bookmark.DevicePermissions.Any(p => p.DeviceId == deviceId)))
            {
                return null;
            }
        }

        return MapToDto(bookmark);
    }

    /// <inheritdoc />
    public async Task<BookmarkDto> CreateBookmarkAsync(Guid userId, CreateBookmarkRequest request)
    {
        var now = DateTime.UtcNow;

        // 获取当前最大排序值
        var maxOrder = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId && b.FolderId == request.FolderId)
            .MaxAsync(b => b.Order);

        var bookmark = new Bookmark
        {
            Id = Guid.NewGuid(),
            UserId = userId,
            FolderId = request.FolderId,
            Title = request.Title,
            Url = request.Url,
            Description = request.Description,
            Icon = request.Icon,
            Visibility = request.Visibility,
            VisitCount = 0,
            Order = maxOrder + 1,
            CreatedAt = now,
            UpdatedAt = now
        };

        await _freeSql.Insert(bookmark).ExecuteAffrowsAsync();

        // 处理标签
        if (request.Tags != null && request.Tags.Length > 0)
        {
            await SyncBookmarkTagsAsync(userId, bookmark.Id, request.Tags);
        }

        // 处理设备权限
        if (request.AllowedDevices != null && request.AllowedDevices.Length > 0)
        {
            await SyncDevicePermissionsAsync(bookmark.Id, request.AllowedDevices);
        }

        // 重新查询以获取完整数据
        return await GetBookmarkAsync(bookmark.Id, userId, Guid.Empty, true) ?? MapToDto(bookmark);
    }

    /// <inheritdoc />
    public async Task<BookmarkDto?> UpdateBookmarkAsync(Guid bookmarkId, Guid userId, UpdateBookmarkRequest request)
    {
        var bookmark = await _freeSql.Select<Bookmark>()
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .FirstAsync();

        if (bookmark == null)
        {
            return null;
        }

        if (request.UpdateFolder)
        {
            bookmark.FolderId = request.FolderId;
        }

        if (!string.IsNullOrEmpty(request.Title))
        {
            bookmark.Title = request.Title;
        }

        if (!string.IsNullOrEmpty(request.Url))
        {
            bookmark.Url = request.Url;
        }

        if (request.Description != null)
        {
            bookmark.Description = request.Description;
        }

        if (request.Icon != null)
        {
            bookmark.Icon = request.Icon;
        }

        if (request.Visibility.HasValue)
        {
            bookmark.Visibility = request.Visibility.Value;
        }

        bookmark.UpdatedAt = DateTime.UtcNow;

        await _freeSql.Update<Bookmark>()
            .SetSource(bookmark)
            .ExecuteAffrowsAsync();

        // 处理标签
        if (request.Tags != null)
        {
            await SyncBookmarkTagsAsync(userId, bookmarkId, request.Tags);
        }

        // 处理设备权限
        if (request.AllowedDevices != null)
        {
            await SyncDevicePermissionsAsync(bookmarkId, request.AllowedDevices);
        }

        return await GetBookmarkAsync(bookmarkId, userId, Guid.Empty, true);
    }

    /// <inheritdoc />
    public async Task<bool> DeleteBookmarkAsync(Guid bookmarkId, Guid userId)
    {
        // 先删除关联数据
        await _freeSql.Delete<BookmarkTag>()
            .Where(bt => bt.BookmarkId == bookmarkId)
            .ExecuteAffrowsAsync();

        await _freeSql.Delete<BookmarkDevicePermission>()
            .Where(p => p.BookmarkId == bookmarkId)
            .ExecuteAffrowsAsync();

        await _freeSql.Delete<CollectionBookmark>()
            .Where(cb => cb.BookmarkId == bookmarkId)
            .ExecuteAffrowsAsync();

        await _freeSql.Delete<BookmarkVisit>()
            .Where(v => v.BookmarkId == bookmarkId)
            .ExecuteAffrowsAsync();

        // 删除书签
        var affectedRows = await _freeSql.Delete<Bookmark>()
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .ExecuteAffrowsAsync();

        return affectedRows > 0;
    }

    /// <inheritdoc />
    public async Task<int> BatchDeleteBookmarksAsync(Guid userId, Guid[] bookmarkIds)
    {
        // 先删除关联数据
        await _freeSql.Delete<BookmarkTag>()
            .Where(bt => bookmarkIds.Contains(bt.BookmarkId))
            .ExecuteAffrowsAsync();

        await _freeSql.Delete<BookmarkDevicePermission>()
            .Where(p => bookmarkIds.Contains(p.BookmarkId))
            .ExecuteAffrowsAsync();

        await _freeSql.Delete<CollectionBookmark>()
            .Where(cb => bookmarkIds.Contains(cb.BookmarkId))
            .ExecuteAffrowsAsync();

        await _freeSql.Delete<BookmarkVisit>()
            .Where(v => bookmarkIds.Contains(v.BookmarkId))
            .ExecuteAffrowsAsync();

        // 删除书签
        var affectedRows = await _freeSql.Delete<Bookmark>()
            .Where(b => b.UserId == userId && bookmarkIds.Contains(b.Id))
            .ExecuteAffrowsAsync();

        return affectedRows;
    }

    /// <inheritdoc />
    public async Task<bool> SetVisibilityAsync(Guid bookmarkId, Guid userId, VisibilityType visibility, Guid[]? allowedDevices)
    {
        var affectedRows = await _freeSql.Update<Bookmark>()
            .Set(b => b.Visibility, visibility)
            .Set(b => b.UpdatedAt, DateTime.UtcNow)
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .ExecuteAffrowsAsync();

        if (affectedRows > 0 && allowedDevices != null)
        {
            await SyncDevicePermissionsAsync(bookmarkId, allowedDevices);
        }

        return affectedRows > 0;
    }

    /// <inheritdoc />
    public async Task<bool> RecordVisitAsync(Guid bookmarkId, Guid userId, Guid? deviceId = null)
    {
        var bookmark = await _freeSql.Select<Bookmark>()
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .FirstAsync();

        if (bookmark == null)
        {
            return false;
        }

        // 更新书签访问统计
        await _freeSql.Update<Bookmark>()
            .Set(b => b.VisitCount, bookmark.VisitCount + 1)
            .Set(b => b.LastVisitAt, DateTime.UtcNow)
            .Where(b => b.Id == bookmarkId)
            .ExecuteAffrowsAsync();

        // 记录访问历史
        var visit = new BookmarkVisit
        {
            Id = Guid.NewGuid(),
            UserId = userId,
            BookmarkId = bookmarkId,
            DeviceId = deviceId,
            VisitedAt = DateTime.UtcNow
        };

        await _freeSql.Insert(visit).ExecuteAffrowsAsync();

        return true;
    }

    /// <inheritdoc />
    public async Task<bool> UpdateOrderAsync(Guid bookmarkId, Guid userId, int newOrder)
    {
        var affectedRows = await _freeSql.Update<Bookmark>()
            .Set(b => b.Order, newOrder)
            .Set(b => b.UpdatedAt, DateTime.UtcNow)
            .Where(b => b.Id == bookmarkId && b.UserId == userId)
            .ExecuteAffrowsAsync();

        return affectedRows > 0;
    }

    /// <inheritdoc />
    public async Task<bool> UrlExistsAsync(Guid userId, string url)
    {
        return await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId && b.Url == url)
            .AnyAsync();
    }

    /// <inheritdoc />
    public async Task<int> ImportBookmarksAsync(Guid userId, List<CreateBookmarkRequest> bookmarks)
    {
        var now = DateTime.UtcNow;
        var maxOrder = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId)
            .MaxAsync(b => b.Order);
        var importedCount = 0;

        foreach (var request in bookmarks)
        {
            // 检查 URL 是否已存在
            var exists = await UrlExistsAsync(userId, request.Url);
            if (exists)
            {
                continue;
            }

            var bookmark = new Bookmark
            {
                Id = Guid.NewGuid(),
                UserId = userId,
                FolderId = request.FolderId,
                Title = request.Title,
                Url = request.Url,
                Description = request.Description,
                Icon = request.Icon,
                Visibility = request.Visibility,
                VisitCount = 0,
                Order = maxOrder + importedCount + 1,
                CreatedAt = now,
                UpdatedAt = now
            };

            await _freeSql.Insert(bookmark).ExecuteAffrowsAsync();

            // 处理标签
            if (request.Tags != null && request.Tags.Length > 0)
            {
                await SyncBookmarkTagsAsync(userId, bookmark.Id, request.Tags);
            }

            // 处理设备权限
            if (request.AllowedDevices != null && request.AllowedDevices.Length > 0)
            {
                await SyncDevicePermissionsAsync(bookmark.Id, request.AllowedDevices);
            }

            importedCount++;
        }

        return importedCount;
    }

    /// <inheritdoc />
    public async Task<List<BookmarkDto>> ExportBookmarksAsync(Guid userId)
    {
        var bookmarks = await _freeSql.Select<Bookmark>()
            .Where(b => b.UserId == userId)
            .IncludeMany(b => b.BookmarkTags, then => then.Include(bt => bt.Tag))
            .IncludeMany(b => b.DevicePermissions)
            .OrderByDescending(b => b.Order)
            .ToListAsync();

        return bookmarks.Select(MapToDto).ToList();
    }

    /// <summary>
    /// 同步书签标签
    /// </summary>
    private async Task SyncBookmarkTagsAsync(Guid userId, Guid bookmarkId, string[] tagNames)
    {
        // 删除现有关联
        await _freeSql.Delete<BookmarkTag>()
            .Where(bt => bt.BookmarkId == bookmarkId)
            .ExecuteAffrowsAsync();

        if (tagNames.Length == 0)
        {
            return;
        }

        // 获取或创建标签
        var existingTags = await _freeSql.Select<Tag>()
            .Where(t => t.UserId == userId && tagNames.Contains(t.Name))
            .ToListAsync();

        var existingTagNames = existingTags.Select(t => t.Name).ToHashSet();
        var newTagNames = tagNames.Where(n => !existingTagNames.Contains(n)).ToList();

        // 创建新标签
        var maxOrder = existingTags.Count > 0
            ? await _freeSql.Select<Tag>().Where(t => t.UserId == userId).MaxAsync(t => t.Order)
            : 0;

        foreach (var tagName in newTagNames)
        {
            var newTag = new Tag
            {
                Id = Guid.NewGuid(),
                UserId = userId,
                Name = tagName,
                Order = ++maxOrder,
                CreatedAt = DateTime.UtcNow
            };

            await _freeSql.Insert(newTag).ExecuteAffrowsAsync();
            existingTags.Add(newTag);
        }

        // 创建关联
        var bookmarkTags = existingTags
            .Where(t => tagNames.Contains(t.Name))
            .Select(t => new BookmarkTag
            {
                Id = Guid.NewGuid(),
                BookmarkId = bookmarkId,
                TagId = t.Id,
                CreatedAt = DateTime.UtcNow
            })
            .ToList();

        await _freeSql.Insert(bookmarkTags).ExecuteAffrowsAsync();
    }

    /// <summary>
    /// 同步设备权限
    /// </summary>
    private async Task SyncDevicePermissionsAsync(Guid bookmarkId, Guid[] deviceIds)
    {
        // 删除现有权限
        await _freeSql.Delete<BookmarkDevicePermission>()
            .Where(p => p.BookmarkId == bookmarkId)
            .ExecuteAffrowsAsync();

        if (deviceIds.Length == 0)
        {
            return;
        }

        // 创建新权限
        var permissions = deviceIds.Select(deviceId => new BookmarkDevicePermission
        {
            Id = Guid.NewGuid(),
            BookmarkId = bookmarkId,
            DeviceId = deviceId,
            CreatedAt = DateTime.UtcNow
        }).ToList();

        await _freeSql.Insert(permissions).ExecuteAffrowsAsync();
    }

    private static BookmarkDto MapToDto(Bookmark bookmark)
    {
        return new BookmarkDto
        {
            Id = bookmark.Id,
            FolderId = bookmark.FolderId,
            Title = bookmark.Title,
            Url = bookmark.Url,
            Description = bookmark.Description,
            Icon = bookmark.Icon,
            Tags = bookmark.BookmarkTags?
                .Where(bt => bt.Tag != null)
                .Select(bt => new TagDto
                {
                    Id = bt.Tag!.Id,
                    Name = bt.Tag.Name,
                    Color = bt.Tag.Color,
                    Icon = bt.Tag.Icon,
                    Order = bt.Tag.Order
                })
                .ToList() ?? new List<TagDto>(),
            VisitCount = bookmark.VisitCount,
            LastVisitAt = bookmark.LastVisitAt,
            Order = bookmark.Order,
            Visibility = bookmark.Visibility,
            AllowedDevices = bookmark.DevicePermissions?
                .Select(p => p.DeviceId)
                .ToArray(),
            CreatedAt = bookmark.CreatedAt,
            UpdatedAt = bookmark.UpdatedAt
        };
    }
}
