using Netina.Core.BaseServices.Abstracts;
using Netina.Domain.MartenEntities.Pages;

namespace Netina.Core.BaseServices;

public class PageService(
    IMartenRepositoryWrapper martenRepositoryWrapperWrapper,
    ICurrentUserService currentUserService,
    ISettingService settingService)
    : IPageService
{
    public async Task<BasePageSDto> GetPageAsync(Guid? id = null, string? pageName = null, string? pageSlug = null, string? type = null, CancellationToken cancellationToken = default)
    {
        BasePage? page = null;
        if (id != null)
            page = await martenRepositoryWrapperWrapper.SetRepository<BasePage>().GetEntityAsync(id.Value, cancellationToken);
        else if (pageSlug != null)
            page = await martenRepositoryWrapperWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Slug == pageSlug, cancellationToken);
        else if (pageName != null)
            page = await martenRepositoryWrapperWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Title == pageName, cancellationToken);
        else if (type != null)
            page = await martenRepositoryWrapperWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Type == type, cancellationToken);
        if (page == null)
            throw new AppException("Page not found", ApiResultStatusCode.NotFound);

        var entityType = Assembly.GetAssembly(typeof(DomainConfig))?.GetType(page.Type);
        var dto = new BasePageSDto
        {
            Content = page.Content,
            Description = page.Description,
            Id = page.Id,
            IsCustomPage = page.IsCustomPage,
            IsHtmlBasePage = page.IsHtmlBasePage,
            Title = page.Title,
            Slug = page.Slug,
            Data = page.Data
        };

        return dto;
    }

    public async Task<List<BasePageSDto>> GetPagesAsync(CancellationToken cancellationToken = default)
    {
        List<BasePageSDto> sDtos = new List<BasePageSDto>();
        var pages = await martenRepositoryWrapperWrapper.SetRepository<BasePage>().GetEntitiesAsync(cancellationToken);
        foreach (var page in pages)
        {
            var dto = new BasePageSDto
            {
                Content = page.Content,
                Description = page.Description,
                Id = page.Id,
                IsCustomPage = page.IsCustomPage,
                IsHtmlBasePage = page.IsHtmlBasePage,
                Title = page.Title,
                Slug = page.Slug,
                Data = page.Data,
                CreatedAt = page.CreatedAt,
                ModifiedAt = page.ModifiedAt
            };
            sDtos.Add(dto);
        }
        return sDtos;
    }

    public async Task<bool> CreatePageAsync(PageActionRequestDto entity, CancellationToken cancellationToken = default)
    {
        var basePage = new BasePage
        {
            Content = entity.Content,
            Description = entity.Description,
            Id = Guid.NewGuid(),
            IsCustomPage = entity.IsCustomPage,
            IsHtmlBasePage = entity.IsHtmlBasePage,
            Title = entity.Title,
            Type = entity.Type,
            Slug = entity.Slug,
            CreatedAt = DateTime.Now,
            CreatedBy = currentUserService.UserName ?? string.Empty
        };
        if (!basePage.Type.IsNullOrEmpty())
        {
            var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType(entity.Type);
            basePage.Data = JsonConvert.SerializeObject(((JsonElement)entity.Data).Deserialize(type));
        }
        await martenRepositoryWrapperWrapper.SetRepository<BasePage>().AddOrUpdateEntityAsync(basePage, cancellationToken);
        return true;
    }

    public async Task<bool> DeletePageAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var page = await martenRepositoryWrapperWrapper.SetRepository<BasePage>().GetEntityAsync(p => p.Id == id, cancellationToken);
        if (page == null)
            throw new AppException("Page not found", ApiResultStatusCode.NotFound);
        await martenRepositoryWrapperWrapper.SetRepository<BasePage>().RemoveEntityAsync(page, cancellationToken);
        return true;
    }

    public async Task<string> CheckRedirectAsync(string oldUrl, CancellationToken cancellationToken)
    {
        var setting = await settingService.GetSettingAsync(nameof(PageSetting), cancellationToken);
        var oldEncode = StringExtensions.GetSlug(oldUrl);
        if (setting is PageSetting pageSetting)
        {
            var newLink = pageSetting.RedirectItems.FirstOrDefault(f => f.OldUrl.ToLower().Trim() == oldEncode.ToLower().Trim());
            if (newLink != null)
            {
                var response = newLink.NewUrl[0] == '/' ? newLink.NewUrl : $"/{newLink.NewUrl}";
                return response;
            }
            else
                throw new BaseApiException(ApiResultStatusCode.NotFound, "Url not found");
        }
        throw new BaseApiException(ApiResultStatusCode.NotFound, "PageSetting not found");
    }

    public async Task<bool> CheckDeletedAsync(string url, CancellationToken cancellationToken)
    {
        var setting = await settingService.GetSettingAsync(nameof(PageSetting), cancellationToken);
        if (setting is PageSetting pageSetting)
        {
            var newLink = pageSetting.DeletedPages.FirstOrDefault(f => f.Url.ToLower().Trim() == url.ToLower().Trim());
            return newLink != null;
        }
        throw new BaseApiException(ApiResultStatusCode.NotFound, "PageSetting not found");
    }
}