using DbConnectionLibrairie;
using Entities;
using ManagerInterfaces;
using Microsoft.EntityFrameworkCore;
using OrderCriterias;
using ExtensionsClassLibrairie;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EntityManagers
{
    public class AdministratorEntityManager(MyDbContext dbContext) : IAdministratorManager<AdministratorEntity>
    {
        private MyDbContext dbContext = dbContext;

        public async Task<AdministratorEntity> addAdmin(AdministratorEntity admin)
        {
            var tmp = await dbContext.Administrators.Where(a => a.Username == admin.Username && a.HashedPassword == admin.HashedPassword).FirstOrDefaultAsync();
            if (tmp != null) // <=> he already exist
            {
                return tmp!;
            }
            dbContext.Administrators.Add(admin);
            await dbContext.SaveChangesAsync();
            return await dbContext.Administrators.Where(a => a.Equals(admin)).FirstAsync(); // to get 
        }

        public async Task<AdministratorEntity?> getAdministrator(int id)
        {
            return await dbContext.Administrators.SingleOrDefaultAsync(a => a.Id == id);
        }

        public async Task<AdministratorEntity?> getAdministratorByUsername(string username)
        {
            return await dbContext.Administrators.Where(a => a.Username == username).FirstOrDefaultAsync();
        }

        public async Task<(int nbPages, IEnumerable<AdministratorEntity>? administrators)> getAdministrators(int nb, int count, AdministratorOrderCriteria orderCriteria = AdministratorOrderCriteria.ById)
        {
            int nbEl = getNbElements();
            if(nb < 0 || count < 0 || nb > nbEl/count) return await Task.FromResult<(int nbPages, IEnumerable<AdministratorEntity>? administrators)>((nbEl/count, null));
            var tmp = dbContext.Administrators;
            switch (orderCriteria)
            {
                case AdministratorOrderCriteria.ById:
                    tmp.OrderBy(a => a.Id);
                    break;
                case AdministratorOrderCriteria.ByUserName:
                    tmp.OrderBy(a => a.Username);
                    break;
            }
            return await Task.FromResult<(int nbPages, IEnumerable<AdministratorEntity>? administrators)>((nbEl/count, tmp.Skip((nb-1)*count).Take(count)));
        }

        public int getNbElements()
        {
            return dbContext.Administrators.CountAsync().Result;
        }

        public async Task<AdministratorEntity?> removeAdmin(AdministratorEntity admin)
        {
            var tmp = await dbContext.Administrators.Where(a => a.Username == admin.Username && a.HashedPassword == admin.HashedPassword).FirstOrDefaultAsync();
            if(tmp == null) return await Task.FromResult<AdministratorEntity?>(tmp);
            dbContext.Administrators.Remove(tmp);
            dbContext.SaveChanges();
            return await Task.FromResult<AdministratorEntity?>(tmp);
        }

        public async Task<AdministratorEntity?> removeAdmin(int id)
        {
            var tmp = await getAdministrator(id);
            if (tmp == null) return await Task.FromResult<AdministratorEntity?>(tmp);
            dbContext.Administrators.Remove(tmp);
            dbContext.SaveChanges();
            return await Task.FromResult<AdministratorEntity?>(tmp);
        }

        public async Task<bool> setPassword(string username, string newHashedPassword)
        {
            var tmp = await getAdministratorByUsername(username);
            if (tmp == null) return await Task.FromResult<bool>(false);
            tmp.HashedPassword = newHashedPassword;
            await dbContext.SaveChangesAsync();
            return await Task.FromResult<bool>(true);
        }

        public async Task<AdministratorEntity?> updateAdministrator(int id, AdministratorEntity admin)
        {
            var tmp = await getAdministrator(id);
            if (tmp == null) return null;
            tmp.Username = admin.Username;
            tmp.HashedPassword = admin.HashedPassword;
            await dbContext.SaveChangesAsync();
            return tmp;
        }
    }
}
