using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RR3CommunityServer.Data;
using RR3CommunityServer.Models;

namespace RR3CommunityServer.Controllers;

[ApiController]
[Route("synergy/friends")]
public class FriendsController : ControllerBase
{
    private readonly RR3DbContext _context;
    private readonly ILogger<FriendsController> _logger;

    public FriendsController(RR3DbContext context, ILogger<FriendsController> logger)
    {
        _context = context;
        _logger = logger;
    }

    // ===== FRIEND MANAGEMENT (4 endpoints) =====

    // GET /synergy/friends/list - Get player's friend list
    [HttpGet("list")]
    public async Task<ActionResult<FriendsListResponse>> GetFriendsList([FromQuery] string synergyId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new FriendsListResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            // Get friends where user is either User1 or User2
            var friends = await _context.Friends
                .Where(f => f.User1Id == user.Id || f.User2Id == user.Id)
                .Include(f => f.User1)
                .Include(f => f.User2)
                .ToListAsync();

            var friendDtos = friends.Select(f =>
            {
                var friend = f.User1Id == user.Id ? f.User2 : f.User1;
                return new FriendDto
                {
                    UserId = friend!.Id,
                    Nickname = friend.Nickname ?? "Player",
                    SynergyId = friend.SynergyId,
                    Level = friend.Level ?? 1,
                    LastOnline = friend.CreatedAt,
                    FriendsSince = f.CreatedAt
                };
            }).ToList();

            return Ok(new FriendsListResponse
            {
                ResultCode = 0,
                Friends = friendDtos,
                TotalCount = friendDtos.Count
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting friends list for {SynergyId}", synergyId);
            return Ok(new FriendsListResponse 
            { 
                ResultCode = -1, 
                Message = "Error loading friends" 
            });
        }
    }

    // POST /synergy/friends/add - Send friend request
    [HttpPost("add")]
    public async Task<ActionResult<SimpleResponse>> SendFriendRequest(
        [FromQuery] string synergyId, 
        [FromQuery] string? targetSynergyId = null,
        [FromQuery] string? targetUsername = null)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            // Find target user by SynergyId or Username
            User? targetUser = null;
            if (!string.IsNullOrEmpty(targetSynergyId))
            {
                targetUser = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == targetSynergyId);
            }
            else if (!string.IsNullOrEmpty(targetUsername))
            {
                targetUser = await _context.Users.FirstOrDefaultAsync(u => u.Nickname == targetUsername);
            }

            if (targetUser == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -2, 
                    Message = "Target user not found" 
                });
            }

            if (user.Id == targetUser.Id)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -3, 
                    Message = "Cannot add yourself as friend" 
                });
            }

            // Check if already friends
            var existingFriendship = await _context.Friends
                .AnyAsync(f => (f.User1Id == user.Id && f.User2Id == targetUser.Id) ||
                              (f.User1Id == targetUser.Id && f.User2Id == user.Id));

            if (existingFriendship)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -4, 
                    Message = "Already friends" 
                });
            }

            // Check for existing pending invitation
            var existingInvite = await _context.FriendInvitations
                .FirstOrDefaultAsync(i => i.SenderId == user.Id && i.ReceiverId == targetUser.Id && i.Status == "pending");

            if (existingInvite != null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -5, 
                    Message = "Friend request already sent" 
                });
            }

            // Create friend invitation
            var invitation = new FriendInvitation
            {
                SenderId = user.Id,
                ReceiverId = targetUser.Id,
                Status = "pending",
                CreatedAt = DateTime.UtcNow,
                ExpiresAt = DateTime.UtcNow.AddDays(7)
            };

            _context.FriendInvitations.Add(invitation);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Friend request sent: {Sender} -> {Receiver}", user.SynergyId, targetUser.SynergyId);

            return Ok(new SimpleResponse 
            { 
                ResultCode = 0, 
                Message = "Friend request sent" 
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error sending friend request");
            return Ok(new SimpleResponse 
            { 
                ResultCode = -1, 
                Message = "Error sending request" 
            });
        }
    }

    // POST /synergy/friends/accept - Accept friend request
    [HttpPost("accept")]
    public async Task<ActionResult<SimpleResponse>> AcceptFriendRequest(
        [FromQuery] string synergyId,
        [FromQuery] int invitationId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            var invitation = await _context.FriendInvitations
                .FirstOrDefaultAsync(i => i.Id == invitationId && i.ReceiverId == user.Id && i.Status == "pending");

            if (invitation == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -2, 
                    Message = "Invitation not found" 
                });
            }

            if (invitation.ExpiresAt < DateTime.UtcNow)
            {
                invitation.Status = "expired";
                await _context.SaveChangesAsync();
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -3, 
                    Message = "Invitation expired" 
                });
            }

            // Create friendship
            var friendship = new Friend
            {
                User1Id = invitation.SenderId,
                User2Id = invitation.ReceiverId,
                CreatedAt = DateTime.UtcNow
            };

            _context.Friends.Add(friendship);

            // Update invitation status
            invitation.Status = "accepted";
            invitation.RespondedAt = DateTime.UtcNow;

            await _context.SaveChangesAsync();

            _logger.LogInformation("Friend request accepted: {Invitation}", invitationId);

            return Ok(new SimpleResponse 
            { 
                ResultCode = 0, 
                Message = "Friend request accepted" 
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error accepting friend request");
            return Ok(new SimpleResponse 
            { 
                ResultCode = -1, 
                Message = "Error accepting request" 
            });
        }
    }

    // DELETE /synergy/friends/remove - Remove friend
    [HttpDelete("remove")]
    public async Task<ActionResult<SimpleResponse>> RemoveFriend(
        [FromQuery] string synergyId,
        [FromQuery] string friendSynergyId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            var friend = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == friendSynergyId);

            if (user == null || friend == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            var friendship = await _context.Friends
                .FirstOrDefaultAsync(f => (f.User1Id == user.Id && f.User2Id == friend.Id) ||
                                         (f.User1Id == friend.Id && f.User2Id == user.Id));

            if (friendship == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -2, 
                    Message = "Not friends" 
                });
            }

            _context.Friends.Remove(friendship);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Friendship removed: {User1} <-> {User2}", user.SynergyId, friend.SynergyId);

            return Ok(new SimpleResponse 
            { 
                ResultCode = 0, 
                Message = "Friend removed" 
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error removing friend");
            return Ok(new SimpleResponse 
            { 
                ResultCode = -1, 
                Message = "Error removing friend" 
            });
        }
    }

    // ===== SEARCH & DISCOVERY (2 endpoints) =====

    // GET /synergy/friends/search - Search for players
    [HttpGet("search")]
    public async Task<ActionResult<UserSearchResponse>> SearchUsers(
        [FromQuery] string query,
        [FromQuery] string? requestingSynergyId = null,
        [FromQuery] int limit = 20)
    {
        try
        {
            User? requestingUser = null;
            if (!string.IsNullOrEmpty(requestingSynergyId))
            {
                requestingUser = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == requestingSynergyId);
            }

            var users = await _context.Users
                .Where(u => (u.Nickname != null && u.Nickname.Contains(query)) || u.SynergyId.Contains(query))
                .Take(limit)
                .ToListAsync();

            var results = new List<UserSearchResultDto>();

            foreach (var user in users)
            {
                bool isFriend = false;
                bool hasPendingInvite = false;

                if (requestingUser != null)
                {
                    isFriend = await _context.Friends.AnyAsync(f =>
                        (f.User1Id == requestingUser.Id && f.User2Id == user.Id) ||
                        (f.User1Id == user.Id && f.User2Id == requestingUser.Id));

                    hasPendingInvite = await _context.FriendInvitations.AnyAsync(i =>
                        i.SenderId == requestingUser.Id && i.ReceiverId == user.Id && i.Status == "pending");
                }

                results.Add(new UserSearchResultDto
                {
                    UserId = user.Id,
                    Nickname = user.Nickname ?? "Player",
                    SynergyId = user.SynergyId,
                    Level = user.Level ?? 1,
                    IsFriend = isFriend,
                    HasPendingInvite = hasPendingInvite
                });
            }

            return Ok(new UserSearchResponse
            {
                ResultCode = 0,
                Users = results
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error searching users");
            return Ok(new UserSearchResponse 
            { 
                ResultCode = -1, 
                Message = "Error searching users" 
            });
        }
    }

    // GET /synergy/friends/invitations/pending - Get pending friend invitations
    [HttpGet("invitations/pending")]
    public async Task<ActionResult<PendingInvitationsResponse>> GetPendingInvitations([FromQuery] string synergyId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new PendingInvitationsResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            var invitations = await _context.FriendInvitations
                .Where(i => i.ReceiverId == user.Id && i.Status == "pending" && i.ExpiresAt > DateTime.UtcNow)
                .Include(i => i.Sender)
                .OrderByDescending(i => i.CreatedAt)
                .ToListAsync();

            var invitationDtos = invitations.Select(i => new FriendInvitationDto
            {
                InvitationId = i.Id,
                SenderId = i.SenderId,
                SenderNickname = i.Sender!.Nickname ?? "Player",
                SenderSynergyId = i.Sender.SynergyId,
                SenderLevel = i.Sender.Level ?? 1,
                Status = i.Status,
                CreatedAt = i.CreatedAt,
                ExpiresAt = i.ExpiresAt
            }).ToList();

            return Ok(new PendingInvitationsResponse
            {
                ResultCode = 0,
                Invitations = invitationDtos
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting pending invitations");
            return Ok(new PendingInvitationsResponse 
            { 
                ResultCode = -1, 
                Message = "Error loading invitations" 
            });
        }
    }

    // ===== GIFTS (3 endpoints) =====

    // POST /synergy/friends/gift/send - Send gift to friend
    [HttpPost("gift/send")]
    public async Task<ActionResult<SimpleResponse>> SendGift([FromBody] SendGiftRequest request)
    {
        try
        {
            var sender = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == request.SynergyId);
            var receiver = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == request.FriendSynergyId);

            if (sender == null || receiver == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            // Verify they're friends
            var areFriends = await _context.Friends.AnyAsync(f =>
                (f.User1Id == sender.Id && f.User2Id == receiver.Id) ||
                (f.User1Id == receiver.Id && f.User2Id == sender.Id));

            if (!areFriends)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -2, 
                    Message = "Not friends" 
                });
            }

            // Create gift
            var gift = new Gift
            {
                SenderId = sender.Id,
                ReceiverId = receiver.Id,
                GiftType = request.GiftType,
                Amount = request.Amount,
                Message = request.Message,
                SentAt = DateTime.UtcNow,
                ExpiresAt = DateTime.UtcNow.AddDays(7)
            };

            _context.Gifts.Add(gift);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Gift sent: {Sender} -> {Receiver} ({Type} x{Amount})", 
                sender.SynergyId, receiver.SynergyId, request.GiftType, request.Amount);

            return Ok(new SimpleResponse 
            { 
                ResultCode = 0, 
                Message = "Gift sent" 
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error sending gift");
            return Ok(new SimpleResponse 
            { 
                ResultCode = -1, 
                Message = "Error sending gift" 
            });
        }
    }

    // GET /synergy/friends/gifts/pending - Get pending gifts
    [HttpGet("gifts/pending")]
    public async Task<ActionResult<PendingGiftsResponse>> GetPendingGifts([FromQuery] string synergyId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new PendingGiftsResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            var gifts = await _context.Gifts
                .Where(g => g.ReceiverId == user.Id && !g.Claimed && g.ExpiresAt > DateTime.UtcNow)
                .Include(g => g.Sender)
                .OrderByDescending(g => g.SentAt)
                .ToListAsync();

            var giftDtos = gifts.Select(g => new GiftDto
            {
                GiftId = g.Id,
                SenderId = g.SenderId,
                SenderNickname = g.Sender!.Nickname ?? "Player",
                GiftType = g.GiftType,
                Amount = g.Amount,
                Message = g.Message,
                SentAt = g.SentAt,
                ExpiresAt = g.ExpiresAt
            }).ToList();

            return Ok(new PendingGiftsResponse
            {
                ResultCode = 0,
                Gifts = giftDtos
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting pending gifts");
            return Ok(new PendingGiftsResponse 
            { 
                ResultCode = -1, 
                Message = "Error loading gifts" 
            });
        }
    }

    // POST /synergy/friends/gifts/claim - Claim a gift
    [HttpPost("gifts/claim")]
    public async Task<ActionResult<ClaimGiftResponse>> ClaimGift(
        [FromQuery] string synergyId,
        [FromQuery] int giftId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new ClaimGiftResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            var gift = await _context.Gifts
                .FirstOrDefaultAsync(g => g.Id == giftId && g.ReceiverId == user.Id && !g.Claimed);

            if (gift == null)
            {
                return Ok(new ClaimGiftResponse 
                { 
                    ResultCode = -2, 
                    Message = "Gift not found or already claimed" 
                });
            }

            if (gift.ExpiresAt < DateTime.UtcNow)
            {
                return Ok(new ClaimGiftResponse 
                { 
                    ResultCode = -3, 
                    Message = "Gift expired" 
                });
            }

            // Mark gift as claimed
            gift.Claimed = true;
            gift.ClaimedAt = DateTime.UtcNow;

            // Add rewards to user (simplified - adjust based on gift type)
            int newBalance = 0;
            switch (gift.GiftType.ToLower())
            {
                case "gold":
                    user.Gold += gift.Amount;
                    newBalance = user.Gold ?? 0;
                    break;
                case "cash":
                    user.Cash += gift.Amount;
                    newBalance = user.Cash ?? 0;
                    break;
            }

            await _context.SaveChangesAsync();

            _logger.LogInformation("Gift claimed: {User} claimed gift {GiftId} ({Type} x{Amount})", 
                user.SynergyId, giftId, gift.GiftType, gift.Amount);

            return Ok(new ClaimGiftResponse
            {
                ResultCode = 0,
                GiftType = gift.GiftType,
                Amount = gift.Amount,
                NewBalance = newBalance
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error claiming gift");
            return Ok(new ClaimGiftResponse 
            { 
                ResultCode = -1, 
                Message = "Error claiming gift" 
            });
        }
    }

    // ===== CLUBS/TEAMS (3 endpoints) =====

    // GET /synergy/clubs/list - Get available clubs
    [HttpGet("/synergy/clubs/list")]
    public async Task<ActionResult<ClubsListResponse>> GetClubsList(
        [FromQuery] bool publicOnly = true,
        [FromQuery] bool recruitingOnly = false,
        [FromQuery] int limit = 50)
    {
        try
        {
            var query = _context.Clubs.AsQueryable();

            if (publicOnly)
                query = query.Where(c => c.IsPublic);

            if (recruitingOnly)
                query = query.Where(c => c.IsRecruiting);

            var clubs = await query
                .OrderByDescending(c => c.TotalPoints)
                .Take(limit)
                .ToListAsync();

            var clubDtos = new List<ClubDto>();
            foreach (var club in clubs)
            {
                var memberCount = await _context.ClubMembers.CountAsync(m => m.ClubId == club.Id);
                
                clubDtos.Add(new ClubDto
                {
                    ClubId = club.Id,
                    Name = club.Name,
                    Description = club.Description,
                    Tag = club.Tag,
                    MemberCount = memberCount,
                    MaxMembers = club.MaxMembers,
                    IsPublic = club.IsPublic,
                    IsRecruiting = club.IsRecruiting,
                    TotalPoints = club.TotalPoints,
                    CreatedAt = club.CreatedAt
                });
            }

            return Ok(new ClubsListResponse
            {
                ResultCode = 0,
                Clubs = clubDtos
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting clubs list");
            return Ok(new ClubsListResponse 
            { 
                ResultCode = -1, 
                Message = "Error loading clubs" 
            });
        }
    }

    // POST /synergy/clubs/join - Join a club
    [HttpPost("/synergy/clubs/join")]
    public async Task<ActionResult<SimpleResponse>> JoinClub(
        [FromQuery] string synergyId,
        [FromQuery] int clubId)
    {
        try
        {
            var user = await _context.Users.FirstOrDefaultAsync(u => u.SynergyId == synergyId);
            if (user == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -1, 
                    Message = "User not found" 
                });
            }

            var club = await _context.Clubs.FirstOrDefaultAsync(c => c.Id == clubId);
            if (club == null)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -2, 
                    Message = "Club not found" 
                });
            }

            // Check if user is already in a club
            var existingMembership = await _context.ClubMembers
                .AnyAsync(m => m.UserId == user.Id);

            if (existingMembership)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -3, 
                    Message = "Already in a club" 
                });
            }

            // Check if club is full
            var memberCount = await _context.ClubMembers.CountAsync(m => m.ClubId == clubId);
            if (memberCount >= club.MaxMembers)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -4, 
                    Message = "Club is full" 
                });
            }

            // Check if club is recruiting
            if (!club.IsRecruiting && club.OwnerId != user.Id)
            {
                return Ok(new SimpleResponse 
                { 
                    ResultCode = -5, 
                    Message = "Club is not recruiting" 
                });
            }

            // Add member
            var member = new ClubMember
            {
                ClubId = clubId,
                UserId = user.Id,
                Role = "member",
                JoinedAt = DateTime.UtcNow
            };

            _context.ClubMembers.Add(member);
            await _context.SaveChangesAsync();

            _logger.LogInformation("User {User} joined club {Club}", user.SynergyId, club.Name);

            return Ok(new SimpleResponse 
            { 
                ResultCode = 0, 
                Message = "Joined club successfully" 
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error joining club");
            return Ok(new SimpleResponse 
            { 
                ResultCode = -1, 
                Message = "Error joining club" 
            });
        }
    }

    // GET /synergy/clubs/{clubId}/members - Get club members
    [HttpGet("/synergy/clubs/{clubId}/members")]
    public async Task<ActionResult<ClubMembersResponse>> GetClubMembers(int clubId)
    {
        try
        {
            var club = await _context.Clubs.FirstOrDefaultAsync(c => c.Id == clubId);
            if (club == null)
            {
                return Ok(new ClubMembersResponse 
                { 
                    ResultCode = -1, 
                    Message = "Club not found" 
                });
            }

            var members = await _context.ClubMembers
                .Where(m => m.ClubId == clubId)
                .Include(m => m.User)
                .OrderByDescending(m => m.ContributedPoints)
                .ToListAsync();

            var memberDtos = members.Select(m => new ClubMemberDto
            {
                UserId = m.UserId,
                Nickname = m.User!.Nickname ?? "Player",
                SynergyId = m.User.SynergyId,
                Level = m.User.Level ?? 1,
                Role = m.Role,
                ContributedPoints = m.ContributedPoints,
                JoinedAt = m.JoinedAt
            }).ToList();

            var memberCount = members.Count;

            return Ok(new ClubMembersResponse
            {
                ResultCode = 0,
                Club = new ClubDto
                {
                    ClubId = club.Id,
                    Name = club.Name,
                    Description = club.Description,
                    Tag = club.Tag,
                    MemberCount = memberCount,
                    MaxMembers = club.MaxMembers,
                    IsPublic = club.IsPublic,
                    IsRecruiting = club.IsRecruiting,
                    TotalPoints = club.TotalPoints,
                    CreatedAt = club.CreatedAt
                },
                Members = memberDtos
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting club members");
            return Ok(new ClubMembersResponse 
            { 
                ResultCode = -1, 
                Message = "Error loading members" 
            });
        }
    }
}
