using AyCode.Core.Extensions;
using AyCode.Database.DbSets.Profiles;
using AyCode.Interfaces.Addresses;
using AyCode.Interfaces.Profiles;
using AyCode.Interfaces.Profiles.Dtos;
using AyCode.Interfaces.ServiceProviders;
using AyCode.Interfaces.Users;
using AyCode.Utils.Extensions;
using Microsoft.EntityFrameworkCore;

namespace AyCode.Database.DbSets.Companies;

public static class AcCompanyDbSetExtensions
{
    #region Add, Update, Remove

    public static bool AddCompany<TCompany, TProfile, TAddress>(this IAcCompanyDbSetBase<TCompany> ctx, TCompany company)
        where TCompany : class, IAcCompany<TProfile, TAddress>
        where TProfile : class, IAcProfile<TAddress>
        where TAddress : class, IAcAddress
    {
        if (company.Profile == null!)
            company.SetProfile((Activator.CreateInstance(typeof(TProfile), company.ProfileId, company.Name) as TProfile)!);

        if (company.Profile!.Address == null!)
            company.Profile.SetAddress((Activator.CreateInstance(typeof(TAddress), company.Profile.AddressId, company.Name) as TAddress)!);

        if (!company.OwnerId.IsNullOrEmpty())
            company.AddUser(company.OwnerId.Value, 1);

        return ctx.Companies.Add(company).State == EntityState.Added;
    }

    public static bool UpdateCompany<TCompany, TProfile, TAddress, TUserToCompany>(this IAcCompanyDbSetBase<TCompany, TProfile, TAddress, TUserToCompany> ctx, TCompany company)
        where TCompany : class, IAcCompany<TProfile, TAddress>
        where TProfile : class, IAcProfile<TAddress>
        where TAddress : class, IAcAddress
        where TUserToCompany : class, IAcUserToCompanyBase
    {
        var companyProfile = company.Profile;

        if (company.ProfileId.IsNullOrEmpty() || companyProfile.Id != company.ProfileId || companyProfile.AddressId.IsNullOrEmpty() || companyProfile.Address.Id != companyProfile.AddressId)
        {
            return false;
        }

        var ownerId = company.OwnerId;
        if (!ownerId.IsNullOrEmpty() && !company.HasUser(ownerId.Value))
        {
            if (!ctx.UserToCompanies.Any(x => x.UserId == company.OwnerId && x.ServiceProviderId == company.Id))
            {
                var userToCompany = (Activator.CreateInstance(typeof(TUserToCompany)) as TUserToCompany)!;
                userToCompany.Id = Guid.NewGuid();
                userToCompany.ServiceProviderId = company.Id;
                userToCompany.UserId = ownerId.Value;
                userToCompany.Permissions = 1;

                ctx.UserToCompanies.Add(userToCompany);
                //company.AddUser(ownerId.Value, 1);
            }
        }

        return ctx.Companies.Update(company).State == EntityState.Modified;
    }

    private static bool RemoveCompany<TCompany, TProfile, TAddress, TUserToCompany>(this IAcCompanyDbSetBase<TCompany, TProfile, TAddress, TUserToCompany> ctx, TCompany company) 
        where TCompany : class, IAcCompany<TProfile, TAddress>
        where TProfile : class, IAcProfile<TAddress>
        where TAddress : class, IAcAddress
        where TUserToCompany : class, IAcUserToCompanyBase
    {
        ctx.RemoveProfile(company.ProfileId);
        ctx.UserToCompanies.RemoveRange(ctx.UserToCompanies.Where(x => x.ServiceProviderId == company.Id));

        //TODO: RemoveProduct, UserToProduct, etc... - J.
        return ctx.Companies.Remove(company).State == EntityState.Deleted;
    }

    public static bool RemoveCompany<TCompany, TProfile, TAddress, TUserToCompany>(this IAcCompanyDbSetBase<TCompany, TProfile, TAddress, TUserToCompany> ctx, Guid companyId) 
        where TCompany : class, IAcCompany<TProfile, TAddress>
        where TProfile : class, IAcProfile<TAddress>
        where TAddress : class, IAcAddress
        where TUserToCompany : class, IAcUserToCompanyBase
    {
        var company = ctx.GetCompanyById(companyId);
        return company == null || ctx.RemoveCompany(company);
    }

    #endregion Add, Update, Remove

    public static TCompany? GetCompanyById<TCompany>(this IAcCompanyDbSetBase<TCompany> ctx, Guid companyId) where TCompany : class, IAcCompanyBase
        => ctx.Companies.FirstOrDefault(x => x.Id == companyId);

    public static IQueryable<TCompany> GetCompanies<TCompany>(this IAcCompanyDbSetBase<TCompany> ctx) where TCompany : class, IAcCompanyBase
        => ctx.Companies;

    public static List<TCompany> GetCompaniesByOwnerId<TCompany>(this IAcCompanyDbSetBase<TCompany> ctx, Guid ownerId) where TCompany : class, IAcCompanyBase
        => ctx.Companies.Where(x => x.OwnerId == ownerId).ToList();
}