using Grand.Business.Core.Interfaces.Common.Localization;
using Grand.Business.Core.Interfaces.Common.Stores;
using Grand.Business.Core.Interfaces.Marketing.Campaigns;
using Grand.Business.Core.Interfaces.Marketing.Newsletters;
using Grand.Business.Core.Interfaces.Messages;
using Grand.Business.Core.Utilities.Common.Security;
using Grand.Domain.Messages;
using Grand.Infrastructure;
using Grand.SharedKernel;
using Grand.SharedKernel.Extensions;
using Grand.Web.Admin.Interfaces;
using Grand.Web.Admin.Models.Messages;
using Grand.Web.Common.DataSource;
using Grand.Web.Common.Filters;
using Grand.Web.Common.Security.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Grand.Web.Admin.Controllers;

[PermissionAuthorize(PermissionSystemName.Campaigns)]
public class CampaignController : BaseAdminController
{
    private readonly ICampaignService _campaignService;
    private readonly ICampaignViewModelService _campaignViewModelService;
    private readonly IEmailAccountService _emailAccountService;
    private readonly EmailAccountSettings _emailAccountSettings;
    private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService;
    private readonly IStoreService _storeService;
    private readonly ITranslationService _translationService;
    private readonly IWorkContext _workContext;

    public CampaignController(ICampaignService campaignService, ICampaignViewModelService campaignViewModelService,
        IEmailAccountService emailAccountService,
        INewsLetterSubscriptionService newsLetterSubscriptionService,
        ITranslationService translationService,
        IWorkContext workContext,
        IStoreService storeService,
        EmailAccountSettings emailAccountSettings)
    {
        _campaignService = campaignService;
        _campaignViewModelService = campaignViewModelService;
        _emailAccountService = emailAccountService;
        _emailAccountSettings = emailAccountSettings;
        _newsLetterSubscriptionService = newsLetterSubscriptionService;
        _translationService = translationService;
        _workContext = workContext;
        _storeService = storeService;
    }

    public IActionResult Index()
    {
        return RedirectToAction("List");
    }

    public IActionResult List()
    {
        return View();
    }

    [PermissionAuthorizeAction(PermissionActionName.List)]
    [HttpPost]
    public async Task<IActionResult> List(DataSourceRequest command)
    {
        var model = await _campaignViewModelService.PrepareCampaignModels();
        var gridModel = new DataSourceResult {
            Data = model.campaignModels,
            Total = model.totalCount
        };
        return Json(gridModel);
    }

    [PermissionAuthorizeAction(PermissionActionName.List)]
    [HttpPost]
    public async Task<IActionResult> Customers(string campaignId, DataSourceRequest command)
    {
        var campaign = await _campaignService.GetCampaignById(campaignId);
        var customers = await _campaignService.CustomerSubscriptions(campaign, command.Page - 1, command.PageSize);

        var gridModel = new DataSourceResult {
            Data = customers,
            Total = customers.TotalCount
        };
        return Json(gridModel);
    }

    [PermissionAuthorizeAction(PermissionActionName.Edit)]
    [HttpPost]
    public async Task<IActionResult> History(string campaignId, DataSourceRequest command)
    {
        var campaign = await _campaignService.GetCampaignById(campaignId);
        var history = await _campaignService.GetCampaignHistory(campaign, command.Page - 1, command.PageSize);

        var gridModel = new DataSourceResult {
            Data = history.Select(x => new {
                x.Email,
                SentDate = x.CreatedDateUtc
            }),
            Total = history.TotalCount
        };
        return Json(gridModel);
    }

    [PermissionAuthorizeAction(PermissionActionName.Export)]
    public async Task<IActionResult> ExportCsv(string campaignId)
    {
        try
        {
            var campaign = await _campaignService.GetCampaignById(campaignId);
            var customers = await _campaignService.CustomerSubscriptions(campaign);

            var sb = new StringBuilder();
            foreach (var subscription in customers.Select(x => x.Email).ToList())
            {
                sb.Append(subscription);
                sb.Append(Environment.NewLine); //new line
            }

            var fileName =
                $"newsletter_emails_campaign_{campaign.Name}_{CommonHelper.GenerateRandomDigitCode(4)}.txt";
            return File(Encoding.UTF8.GetBytes(sb.ToString()), "text/csv", fileName);
        }
        catch (Exception exc)
        {
            Error(exc);
            return RedirectToAction("List");
        }
    }

    [PermissionAuthorizeAction(PermissionActionName.Create)]
    public async Task<IActionResult> Create()
    {
        var model = await _campaignViewModelService.PrepareCampaignModel();
        return View(model);
    }

    [PermissionAuthorizeAction(PermissionActionName.Edit)]
    [HttpPost]
    [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")]
    public async Task<IActionResult> Create(CampaignModel model, bool continueEditing)
    {
        if (ModelState.IsValid)
        {
            var campaign = await _campaignViewModelService.InsertCampaignModel(model);

            Success(_translationService.GetResource("admin.marketing.Campaigns.Added"));
            return continueEditing ? RedirectToAction("Edit", new { id = campaign.Id }) : RedirectToAction("List");
        }

        model = await _campaignViewModelService.PrepareCampaignModel(model);

        return View(model);
    }

    [PermissionAuthorizeAction(PermissionActionName.Preview)]
    public async Task<IActionResult> Edit(string id)
    {
        var campaign = await _campaignService.GetCampaignById(id);
        if (campaign == null)
            //No campaign found with the specified id
            return RedirectToAction("List");

        var model = await _campaignViewModelService.PrepareCampaignModel(campaign);
        return View(model);
    }

    [PermissionAuthorizeAction(PermissionActionName.Edit)]
    [HttpPost]
    [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")]
    public async Task<IActionResult> Edit(CampaignModel model, bool continueEditing)
    {
        var campaign = await _campaignService.GetCampaignById(model.Id);
        if (campaign == null)
            //No campaign found with the specified id
            return RedirectToAction("List");

        if (ModelState.IsValid)
        {
            campaign = await _campaignViewModelService.UpdateCampaignModel(campaign, model);
            Success(_translationService.GetResource("admin.marketing.Campaigns.Updated"));
            //selected tab
            await SaveSelectedTabIndex();

            return continueEditing ? RedirectToAction("Edit", new { id = campaign.Id }) : RedirectToAction("List");
        }

        model = await _campaignViewModelService.PrepareCampaignModel(model);
        return View(model);
    }

    [PermissionAuthorizeAction(PermissionActionName.Edit)]
    [HttpPost]
    public async Task<IActionResult> SendTestEmail(CampaignModel model)
    {
        var campaign = await _campaignService.GetCampaignById(model.Id);
        if (campaign == null)
            //No campaign found with the specified id
            return RedirectToAction("List");

        model = await _campaignViewModelService.PrepareCampaignModel(model);
        try
        {
            var emailAccount =
                await _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId);
            if (emailAccount == null)
                throw new GrandException("Email account could not be loaded");

            var subscription =
                await _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmailAndStoreId(model.TestEmail,
                    _workContext.CurrentStore.Id);
            if (subscription != null)
            {
                //there's a subscription. use it
                var subscriptions = new List<NewsLetterSubscription> {
                    subscription
                };
                await _campaignService.SendCampaign(campaign, emailAccount, subscriptions);
            }
            else
            {
                //no subscription found
                await _campaignService.SendCampaign(campaign, emailAccount, model.TestEmail);
            }

            Success(_translationService.GetResource("admin.marketing.Campaigns.TestEmailSentToCustomers"), false);
            return RedirectToAction("Edit", new { id = campaign.Id });
        }
        catch (Exception exc)
        {
            Error(exc, false);
        }

        //If we got this far, something failed, redisplay form
        return RedirectToAction("Edit", new { id = campaign.Id });
    }

    [PermissionAuthorizeAction(PermissionActionName.Edit)]
    [HttpPost]
    public async Task<IActionResult> SendMassEmail(CampaignModel model)
    {
        var campaign = await _campaignService.GetCampaignById(model.Id);
        if (campaign == null)
            //No campaign found with the specified id
            return RedirectToAction("List");

        model = await _campaignViewModelService.PrepareCampaignModel(model);
        model.CustomerTags = campaign.CustomerTags.ToList();
        model.CustomerGroups = campaign.CustomerGroups.ToList();
        try
        {
            var emailAccount = await _emailAccountService.GetEmailAccountById(campaign.EmailAccountId);
            if (emailAccount == null)
                throw new GrandException("Email account could not be loaded");

            //subscribers of certain store?
            var store = await _storeService.GetStoreById(campaign.StoreId);
            var subscriptions = await _campaignService.CustomerSubscriptions(campaign);
            var totalEmailsSent = await _campaignService.SendCampaign(campaign, emailAccount, subscriptions);
            Success(
                string.Format(_translationService.GetResource("admin.marketing.Campaigns.MassEmailSentToCustomers"),
                    totalEmailsSent), false);
            return RedirectToAction("Edit", new { id = campaign.Id });
        }
        catch (Exception exc)
        {
            Error(exc, false);
        }

        //If we got this far, something failed, redisplay form
        return RedirectToAction("Edit", new { id = campaign.Id });
    }

    [PermissionAuthorizeAction(PermissionActionName.Delete)]
    [HttpPost]
    public async Task<IActionResult> Delete(string id)
    {
        var campaign = await _campaignService.GetCampaignById(id);
        if (campaign == null)
            //No campaign found with the specified id
            return RedirectToAction("List");

        if (ModelState.IsValid)
        {
            await _campaignService.DeleteCampaign(campaign);
            Success(_translationService.GetResource("admin.marketing.Campaigns.Deleted"));
            return RedirectToAction("List");
        }

        Error(ModelState);
        return RedirectToAction("Edit", new { id });
    }
}