using Managing.Application.Abstractions.Repositories;
using Managing.Domain.Users;
using Microsoft.EntityFrameworkCore;

namespace Managing.Infrastructure.Databases.PostgreSql;

public class PostgreSqlUserRepository : IUserRepository
{
    private readonly ManagingDbContext _context;

    public PostgreSqlUserRepository(ManagingDbContext context)
    {
        _context = context;
    }



    public async Task<User> GetUserByAgentNameAsync(string agentName)
    {
        try
        {
            await PostgreSqlConnectionHelper.EnsureConnectionOpenAsync(_context);

            var userEntity = await _context.Users
                .AsNoTracking()
                .FirstOrDefaultAsync(u => u.AgentName == agentName)
                .ConfigureAwait(false);

            return PostgreSqlMappers.Map(userEntity);
        }
        finally
        {
            // Always ensure the connection is closed after the operation
            await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
        }
    }

    public async Task<User> GetUserByNameAsync(string name)
    {
        try
        {
            await PostgreSqlConnectionHelper.EnsureConnectionOpenAsync(_context);

            var userEntity = await _context.Users
                .AsNoTracking()
                .FirstOrDefaultAsync(u => u.Name == name)
                .ConfigureAwait(false);

            return PostgreSqlMappers.Map(userEntity);
        }
        finally
        {
            // Always ensure the connection is closed after the operation
            await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
        }
    }

    public async Task<IEnumerable<User>> GetAllUsersAsync()
    {
        try
        {
            await PostgreSqlConnectionHelper.EnsureConnectionOpenAsync(_context);

            var userEntities = await _context.Users
                .AsNoTracking()
                .ToListAsync()
                .ConfigureAwait(false);

            return userEntities.Select(PostgreSqlMappers.Map);
        }
        finally
        {
            // Always ensure the connection is closed after the operation
            await PostgreSqlConnectionHelper.SafeCloseConnectionAsync(_context);
        }
    }

    public async Task SaveOrUpdateUserAsync(User user)
    {
        try
        {
            var existingUser = await _context.Users
                .AsTracking()
                .FirstOrDefaultAsync(u => u.Name == user.Name)
                .ConfigureAwait(false);

            if (existingUser != null)
            {
                // Update existing user
                existingUser.AgentName = user.AgentName;
                existingUser.AvatarUrl = user.AvatarUrl;
                existingUser.TelegramChannel = user.TelegramChannel;

                _context.Users.Update(existingUser);

                // Update the user object with the existing user's ID
                user.Id = existingUser.Id;
            }
            else
            {
                // Insert new user
                var userEntity = PostgreSqlMappers.Map(user);
                _context.Users.Add(userEntity);

                // Update the user object with the database-generated ID after save
                await _context.SaveChangesAsync().ConfigureAwait(false);
                user.Id = userEntity.Id;
                return; // Exit early since we already saved
            }

            await _context.SaveChangesAsync().ConfigureAwait(false);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw new Exception("Cannot save or update user");
        }
    }
}