@namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IModuleDefinitionService ModuleDefinitionService
@inject IThemeService ThemeService
@inject IModuleService ModuleService
@inject IPageService PageService
@inject IPageModuleService PageModuleService
@inject ILogService logger
@inject ISettingService SettingService
@inject IStringLocalizer<ControlPanel> Localizer

@if (_moduleDefinitions != null && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
{
    <div class="app-controlpanel" style="@_display">

        <div class="@CardClass">
            <div class="@HeaderClass">
                <span class="font-weight-bold">@Localizer["Control Panel"]</span>
                <button type="button" class="close" @onclick="HideControlPanel" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="@BodyClass">

                @if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
                {
                    <div class="row">
                        <div class="col">
                            <button type="button" class="btn btn-primary btn-block mx-auto" @onclick=@(async () => Navigate("Admin"))>@Localizer["Admin Dashboard"]</button>
                        </div>
                    </div>

                    <hr class="app-rule" />

                    <div class="row">
                        <div class="col text-center">
                            <label class="control-label">@Localizer["Page Management:"] </label>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col">
                            <button type="button" class="btn btn-primary btn-block mx-auto" @onclick=@(async () => Navigate("Add"))>@Localizer["Add"]</button>
                        </div>
                        <div class="col">
                            <button type="button" class="btn btn-primary btn-block mx-auto" @onclick=@(async () => Navigate("Edit"))>@Localizer["Edit"]</button>
                        </div>
                        <div class="col">
                            <button class="btn btn-danger btn-block mx-auto" @onclick="ConfirmDelete">@Localizer["Delete"]</button>
                        </div>
                    </div>
                    <br />
                    <div class="row">
                        @if (UserSecurity.GetPermissionStrings(PageState.Page.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(RoleNames.Everyone))
                        {
                            <div class="col">
                                <button type="button" class="btn btn-primary btn-block mx-auto" @onclick=@(async () => Publish("unpublish"))>@Localizer["Unpublish Page"]</button>
                            </div>
                        }
                        else
                        {
                            <div class="col">
                                <button type="button" class="btn btn-primary btn-block mx-auto" @onclick=@(async () => Publish("publish"))>@Localizer["Publish Page"]</button>
                            </div>
                        }
                    </div>
                }

                @if (_deleteConfirmation)
                {
                    <div class="app-admin-modal">
                        <div class="modal" tabindex="-1" role="dialog">
                            <div class="modal-dialog">
                                <div class="modal-content">
                                    <div class="modal-header">
                                        <h5 class="modal-title">@Localizer["Delete Page"]</h5>
                                        <button type="button" class="close" @onclick="ConfirmDelete" aria-label="Close">&times;</button>
                                    </div>
                                    <div class="modal-body">
                                        <p>Are You Sure You Want To Delete This Page?</p>
                                    </div>
                                    <div class="modal-footer">
                                        <button type="button" class="btn btn-danger" @onclick="DeletePage">@Localizer["Delete"]</button>
                                        <button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@Localizer["Cancel"]</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                }
                <hr class="app-rule" />

                <div class="row">
                    <div class="col text-center">
                        <label for="Module" class="control-label">@Localizer["Module Management:"] </label>
                        <select class="form-control" @bind="@ModuleType">
                            <option value="new">@Localizer["Add New Module"]</option>
                            <option value="existing">@Localizer["Add Existing Module"]</option>
                        </select>
                        @if (ModuleType == "new")
                        {
                            @if (_moduleDefinitions != null)
                            {
                                <select class="form-control" @onchange="(e => CategoryChanged(e))">
                                    @foreach (var category in _categories)
                                    {
                                        if (category == Category)
                                        {
                                            <option value="@category" selected>@category @Localizer["Modules"]</option>
                                        }
                                        else
                                        {
                                            <option value="@category">@category @Localizer["Modules"]</option>
                                        }
                                    }
                                </select>
                                <select class="form-control" @onchange="(e => ModuleChanged(e))">
                                    @if (ModuleDefinitionName == "-")
                                    {
                                        <option value="-" selected>&lt;@Localizer["Select Module"]&gt;</option>
                                    }
                                    else
                                    {
                                        <option value="-">&lt;@Localizer["Select Module"]&gt;</option>
                                    }
                                    @foreach (var moduledefinition in _moduleDefinitions)
                                    {
                                        if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
                                        {
                                            if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
                                            {
                                                <option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
                                            }
                                        }
                                    }
                                </select>
                                @((MarkupString) Description)
                            }
                        }
                        else
                        {
                            <select class="form-control" @onchange="(e => PageChanged(e))">
                                <option value="-">&lt;@Localizer["Select Page"]&gt;</option>
                                @foreach (Page p in _pages)
                                {
                                    <option value="@p.PageId">@p.Name</option>
                                }
                            </select>
                            <select class="form-control" @bind="@ModuleId">
                                <option value="-">&lt;@Localizer["Select Module"]&gt;</option>
                                @foreach (Module module in _modules)
                                {
                                    <option value="@module.ModuleId">@module.Title</option>
                                }
                            </select>
                        }
                    </div>
                </div>
                <div class="row">
                    <div class="col text-center">
                        <label for="Title" class="control-label">@Localizer["Title:"] </label>
                        <input type="text" name="Title" class="form-control" @bind="@Title" />
                    </div>
                </div>
                @if (_pane.Length > 1)
                {
                    <div class="row">
                        <div class="col text-center">
                            <label for="Pane" class="control-label">@Localizer["Pane:"] </label>
                            <select class="form-control" @bind="@Pane">
                                @foreach (string pane in PageState.Page.Panes)
                                {
                                    <option value="@pane">@pane Pane</option>
                                }
                            </select>
                        </div>
                    </div>
                }
                <div class="row">
                    <div class="col text-center">
                        <label for="Container" class="control-label">@Localizer["Container:"] </label>
                        <select class="form-control" @bind="@ContainerType">
                            @foreach (var container in _containers)
                            {
                                <option value="@container.TypeName">@container.Name</option>
                            }
                        </select>
                    </div>
                </div>

                <br />

                <button type="button" class="btn btn-primary btn-block mx-auto" @onclick="@AddModule">@Localizer["Add Module To Page"]</button>
                @((MarkupString) Message)
            </div>
        </div>
    </div>
}

@if (ShowLanguageSwitcher)
{
    <LanguageSwitcher />
}

@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) || (PageState.Page.IsPersonalizable && PageState.User != null))
{
    if (PageState.EditMode)
    {
        <button type="button" class="btn @ButtonClass active" data-toggle="button" aria-pressed="true" autocomplete="off" @onclick="(async () => await ToggleEditMode(PageState.EditMode))">
            <span class="oi oi-pencil"></span>
        </button>
    }
    else
    {
        <button type="button" class="btn @ButtonClass" data-toggle="button" aria-pressed="false" autocomplete="off" @onclick="(async () => await ToggleEditMode(PageState.EditMode))">
            <span class="oi oi-pencil"></span>
        </button>
    }
}

@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
{
    <button type="button" class="btn @ButtonClass" @onclick="ShowControlPanel">
        <span class="oi oi-cog"></span>
    </button>
}

@code{

    private bool _deleteConfirmation = false;
    private List<string> _categories = new List<string>();
    private List<ModuleDefinition> _allModuleDefinitions;
    private List<ModuleDefinition> _moduleDefinitions;
    private List<Page> _pages = new List<Page>();
    private List<Module> _modules = new List<Module>();
    private List<ThemeControl> _containers = new List<ThemeControl>();
    private string _display = "display: none;";
    private string _category = "Common";

    protected string PageId { get; private set; } = "-";
    protected string ModuleId { get; private set; } = "-";
    protected string ModuleType { get; private set; } = "new";
    protected string ModuleDefinitionName { get; private set; } = "-";

    protected string Category
    {
        get => _category;
        private set
        {
            if (_category != value)
            {
                _category = value;
                _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
                ModuleDefinitionName = "-";
                Description = "";
                StateHasChanged();
                _ = UpdateSettingsAsync();
            }
        }
    }

    protected string Pane
    {
        get => _pane;
        private set
        {
            if (_pane != value)
            {
                _pane = value;
                _ = UpdateSettingsAsync();
            }
        }
    }


    protected string Description { get; private set; } = "";

    protected string Title { get; private set; } = "";
    protected string ContainerType { get; private set; } = "";
    protected string Message { get; private set; } = "";

    [Parameter]
    public string ButtonClass { get; set; } = "btn-outline-secondary";

    [Parameter]
    public string CardClass { get; set; } = "card border-secondary mb-3";

    [Parameter]
    public string HeaderClass { get; set; } = "card-header";

    [Parameter]
    public string BodyClass { get; set; } = "card-body";

    [Parameter]
    public bool ShowLanguageSwitcher { get; set; } = true;


    protected override async Task OnParametersSetAsync()
    {
        if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
        {
            _pages?.Clear();

            foreach (Page p in PageState.Pages)
            {
                if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
                {
                    _pages.Add(p);
                }
            }
            await LoadSettingsAsync();

            var themes = await ThemeService.GetThemesAsync();
            _containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
            ContainerType = PageState.Site.DefaultContainerType;
            _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
            _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
            _categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
        }
    }

    private void CategoryChanged(ChangeEventArgs e)
    {
        Category = (string)e.Value;
    }

    private void ModuleChanged(ChangeEventArgs e)
    {
        ModuleDefinitionName = (string)e.Value;
        if (ModuleDefinitionName != "-")
        {
            var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
            Description = "<br /><div class=\"alert alert-info\" role=\"alert\">" + moduleDefinition.Description + "</div>";
        }
        else
        {
            Description = "";
        }

        StateHasChanged();
    }

    private void PageChanged(ChangeEventArgs e)
    {
        PageId = (string)e.Value;
        if (PageId != "-")
        {
            _modules = PageState.Modules
                .Where(module => module.PageId == int.Parse(PageId)
                                 && !module.IsDeleted
                                 && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
                .ToList();
        }
        ModuleId = "-";
        StateHasChanged();
    }

    private async Task AddModule()
    {
        if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
        {
            if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
            {
                if (ModuleType == "new")
                {
                    Module module = new Module();
                    module.SiteId = PageState.Site.SiteId;
                    module.PageId = PageState.Page.PageId;
                    module.ModuleDefinitionName = ModuleDefinitionName;
                    module.AllPages = false;

                    // set module view permissions to page edit permissions
                    List<PermissionString> permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions);
                    permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions;
                    module.Permissions = UserSecurity.SetPermissionStrings(permissions);

                    module = await ModuleService.AddModuleAsync(module);
                    ModuleId = module.ModuleId.ToString();
                }

                var pageModule = new PageModule
                {
                    PageId = PageState.Page.PageId,
                    ModuleId = int.Parse(ModuleId),
                    Title = Title
                };
                if (pageModule.Title == "")
                {
                    if (ModuleType == "new")
                    {
                        pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
                    }
                    else
                    {
                        pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
                    }
                }

                pageModule.Pane = Pane;
                pageModule.Order = int.MaxValue;
                pageModule.ContainerType = ContainerType;

                if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
                {
                    pageModule.ContainerType = "";
                }

                await PageModuleService.AddPageModuleAsync(pageModule);
                await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);

                Message = $"<br /><div class=\"alert alert-success\" role=\"alert\">{Localizer["Module Added To Page"]}</div>";
                NavigationManager.NavigateTo(NavigateUrl());
            }
            else
            {
                Message = $"<br /><div class=\"alert alert-warning\" role=\"alert\">{Localizer["You Must Select A Module"]}</div>";
            }
        }
        else
        {
            Message = $"<br /><div class=\"alert alert-error\" role=\"alert\">{Localizer["Not Authorized"]}</div>";
        }
    }

    private async Task ToggleEditMode(bool EditMode)
    {
        if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
        {
            if (EditMode)
            {
                PageState.EditMode = false;
            }
            else
            {
                PageState.EditMode = true;
            }

            NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "1" : "0")));
        }
        else
        {
            if (PageState.Page.IsPersonalizable && PageState.User != null)
            {
                await PageService.AddPageAsync(PageState.Page.PageId, PageState.User.UserId);
                PageState.EditMode = true;
                NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "1" : "0")));
            }
        }
    }

    private void ShowControlPanel()
    {
        Message = "";
        _display = "width: 25%; min-width: 375px;";
        StateHasChanged();
    }

    private void HideControlPanel()
    {
        Message = "";
        _display = "width: 0%;";
        StateHasChanged();
    }

    private void Navigate(string location)
    {
        HideControlPanel();
        Module module;
        switch (location)
        {
            case "Admin":
                // get admin dashboard moduleid
                module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);

                if (module != null)
                {
                    NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, module.ModuleId, "Index", ""));
                }

                break;
            case "Add":
            case "Edit":
                string url = "";
                // get page management moduleid
                module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule);

                if (module != null)
                {
                    switch (location)
                    {
                        case "Add":
                            url = EditUrl(PageState.Page.Path, module.ModuleId, location, "cp=" + PageState.Page.PageId);
                            break;
                        case "Edit":
                            url = EditUrl(PageState.Page.Path, module.ModuleId, location, "id=" + PageState.Page.PageId.ToString() + "&cp=" + PageState.Page.PageId);
                            break;
                    }
                }

                if (url != "")
                {
                    NavigationManager.NavigateTo(url);
                }

                break;
        }
    }

    private async void Publish(string action)
    {
        if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
        {
            List<PermissionString> permissions;

            if (action == "publish")
            {
                // publish all modules
                foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
                {
                    permissions = UserSecurity.GetPermissionStrings(module.Permissions);
                    foreach (var permissionstring in permissions)
                    {
                        if (permissionstring.PermissionName == PermissionNames.View)
                        {
                            List<string> ids = permissionstring.Permissions.Split(';').ToList();
                            if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone);
                            if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered);
                            permissionstring.Permissions = string.Join(";", ids.ToArray());
                        }
                    }
                    module.Permissions = UserSecurity.SetPermissionStrings(permissions);
                    await ModuleService.UpdateModuleAsync(module);
                }
            }

            // publish page
            var page = PageState.Page;
            permissions = UserSecurity.GetPermissionStrings(page.Permissions);
            foreach (var permissionstring in permissions)
            {
                if (permissionstring.PermissionName == PermissionNames.View)
                {
                    List<string> ids = permissionstring.Permissions.Split(';').ToList();
                    switch (action)
                    {
                        case "publish":
                            if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone);
                            if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered);
                            break;
                        case "unpublish":
                            ids.Remove(RoleNames.Everyone);
                            ids.Remove(RoleNames.Registered);
                            break;
                    }
                    permissionstring.Permissions = string.Join(";", ids.ToArray());
                }
            }
            page.Permissions = UserSecurity.SetPermissionStrings(permissions);
            await PageService.UpdatePageAsync(page);
            NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload"));
        }
    }

    private void ConfirmDelete()
    {
        _deleteConfirmation = !_deleteConfirmation;
        StateHasChanged();
    }

    private async Task DeletePage()
    {
        ConfirmDelete();

        var page = PageState.Page;
        try
        {
            if (page.UserId == null)
            {
                page.IsDeleted = true;
                await PageService.UpdatePageAsync(page);
                await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
                NavigationManager.NavigateTo(NavigateUrl(""));
            }
            else // personalized page
            {
                await PageService.DeletePageAsync(page.PageId);
                await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
                NavigationManager.NavigateTo(NavigateUrl());
            }
        }
        catch (Exception ex)
        {
            await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message);
        }
    }

    private string settingCategory = "CP-category";
    private string settingPane = "CP-pane";
    private string _pane = "";

    private async Task LoadSettingsAsync()
    {
        Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
        _category = SettingService.GetSetting(settings, settingCategory, "Common");
        var pane = SettingService.GetSetting(settings, settingPane, "");
        _pane = PageState.Page.Panes.Contains(pane) ? pane : PaneNames.Admin;
    }

    private async Task UpdateSettingsAsync()
    {
        Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
        SettingService.SetSetting(settings, settingCategory, _category);
        SettingService.SetSetting(settings, settingPane, _pane);
        await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
    }

}
