using AutoMapper;
using System.Linq.Expressions;
using salesbook.Shared.Core.Dto;
using salesbook.Shared.Core.Entity;
using salesbook.Shared.Core.Helpers.Enum;
using salesbook.Shared.Core.Interface;

namespace salesbook.Maui.Core.Services;

public class ManageDataService(LocalDbService localDb, IMapper mapper) : IManageDataService
{
    public Task<List<T>> GetTable<T>(Expression<Func<T, bool>>? whereCond = null) where T : new() =>
        localDb.Get(whereCond);

    public async Task<List<ContactDTO>> GetContact()
    {
        var contactList = await localDb.Get<AnagClie>(x => x.FlagStato.Equals("A"));
        var prospectList = await localDb.Get<PtbPros>();

        // Mappa i contatti
        var contactMapper = mapper.Map<List<ContactDTO>>(contactList);

        // Mappa i prospects
        var prospectMapper = mapper.Map<List<ContactDTO>>(prospectList);

        contactMapper.AddRange(prospectMapper);

        return contactMapper;
    }

    public async Task<ContactDTO?> GetSpecificContact(string codAnag, bool isContact)
    {
        if (isContact)
        {
            var contact = (await localDb.Get<AnagClie>(x => x.CodAnag != null && x.CodAnag.Equals(codAnag)))
                .LastOrDefault();

            return contact == null ? null : mapper.Map<ContactDTO>(contact);
        }
        else
        {
            var contact = (await localDb.Get<PtbPros>(x => x.CodPpro != null && x.CodPpro.Equals(codAnag)))
                .LastOrDefault();

            return contact == null ? null : mapper.Map<ContactDTO>(contact);
        }
    }

    public async Task<List<ActivityDTO>> GetActivity(Expression<Func<StbActivity, bool>>? whereCond = null)
    {
        var activities = await localDb.Get(whereCond);

        var codJcomList = activities
            .Select(x => x.CodJcom)
            .Where(x => !string.IsNullOrEmpty(x))
            .Distinct().ToList();

        var jtbComtList = await localDb.Get<JtbComt>(x => codJcomList.Contains(x.CodJcom));
        var commesseDict = jtbComtList.ToDictionary(x => x.CodJcom, x => x.Descrizione);

        var codAnagList = activities
            .Select(x => x.CodAnag)
            .Where(x => !string.IsNullOrEmpty(x))
            .Distinct().ToList();
        var clientList = await localDb.Get<AnagClie>(x => codAnagList.Contains(x.CodAnag));
        var distinctClient = clientList.ToDictionary(x => x.CodAnag, x => x.RagSoc);

        var prospectList = await localDb.Get<PtbPros>(x => codAnagList.Contains(x.CodPpro));
        var distinctProspect = prospectList.ToDictionary(x => x.CodPpro, x => x.RagSoc);

        var returnDto = activities
            .Select(activity =>
            {
                var dto = mapper.Map<ActivityDTO>(activity);

                if (activity.CodJcom != null)
                {
                    dto.Category = ActivityCategoryEnum.Commessa;
                }
                else
                {
                    dto.Category = activity.CodAnag != null ? ActivityCategoryEnum.Interna : ActivityCategoryEnum.Memo;
                }

                if (dto.Category != ActivityCategoryEnum.Memo && activity.CodAnag != null)
                {
                    string? ragSoc;

                    if (distinctClient.TryGetValue(activity.CodAnag, out ragSoc) ||
                        distinctProspect.TryGetValue(activity.CodAnag, out ragSoc))
                    {
                        dto.Cliente = ragSoc;
                    }
                }

                dto.Commessa = activity.CodJcom != null && commesseDict.TryGetValue(activity.CodJcom, out var descr)
                    ? descr
                    : null;
                return dto;
            })
            .ToList();

        return returnDto;
    }

    public Task InsertOrUpdate<T>(List<T> listToSave) => 
        localDb.InsertOrUpdate(listToSave);

    public Task InsertOrUpdate<T>(T objectToSave) =>
        localDb.InsertOrUpdate<T>([objectToSave]);

    public Task Delete<T>(T objectToDelete) =>
        localDb.Delete(objectToDelete);

    public async Task DeleteActivity(ActivityDTO activity)
    {
        await localDb.Delete(
            (await GetTable<StbActivity>(x => x.ActivityId.Equals(activity.ActivityId))).Last()
        );
    }

    public Task ClearDb() =>
        localDb.ResetDb();
}