@namespace Oqtane.Modules.Admin.Pages
@using Oqtane.Interfaces
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@inject IThemeService  ThemeService
@inject IStringLocalizer<Edit> Localizer

<TabStrip Refresh="@_refresh">
    <TabPanel Name="Settings" ResourceKey="Settings">
        @if (_themeList != null)
        {
            <table class="table table-borderless">
                <tr>
                    <td>
                        <Label For="Name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
                    </td>
                    <td>
                        <input id="Name" class="form-control" @bind="@_name" />
                    </td>
                </tr>
                <tr>
                    <td>
                        <Label For="Parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
                    </td>
                    <td>
                        <select id="Parent" class="form-control" value="@_parentid" @onchange="(e => ParentChanged(e))">
                            <option value="-1">&lt;@Localizer["Site Root"]&gt;</option>
                            @foreach (Page page in _pageList)
                            {
                                if (page.PageId != _pageId)
                                {
                                    <option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
                                }
                            }
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        <Label For="Move" HelpText="Select the location where you would like the page to be moved in relation to other pages" ResourceKey="Move">Move: </Label>
                    </td>
                    <td>
                        <select id="Move" class="form-control" @bind="@_insert">
                            @if (_parentid == _currentparentid)
                            {
                                <option value="=">&lt;@Localizer["Maintain Current Location"]&gt;</option>
                            }
                            <option value="<<">@Localizer["To Beginning"]</option>
                            @if (_children != null && _children.Count > 0)
                            {
                                <option value="<">@Localizer["Before"]</option>
                                <option value=">">@Localizer["After"]</option>
                            }
                            <option value=">>">@Localizer["To End"]</option>
                        </select>
                        @if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
                        {
                            <select class="form-control" @bind="@_childid">
                                <option value="-1">&lt;@Localizer["Select Page"]&gt;</option>
                                @foreach (Page page in _children)
                                {
                                    <option value="@(page.PageId)">@(page.Name)</option>
                                }
                            </select>
                        }
                    </td>
                </tr>
                <tr>
                    <td>
                        <Label For="Navigation" HelpText="Select whether the page is part of the site navigation or hidden" ResourceKey="Navigation">Navigation? </Label>
                    </td>
                    <td>
                        <select id="Navigation" class="form-control" @bind="@_isnavigation">
                            <option value="True">@Localizer["Yes"]</option>
                            <option value="False">@Localizer["No"]</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>
                        <Label For="Path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used." ResourceKey="UrlPath">Url Path: </Label>
                    </td>
                    <td>
                        <input id="Path" class="form-control" @bind="@_path" />
                    </td>
                </tr>
                <tr>
                    <td>
                        <Label For="Url" HelpText="Optionally enter a url which this page should redirect to when a user navigates to it" ResourceKey="Redirect">Redirect: </Label>
                    </td>
                    <td>
                        <input id="Url" class="form-control" @bind="@_url" />
                    </td>
                </tr>
            </table>
            <Section Name="Appearance" ResourceKey="Appearance">
                <table class="table table-borderless">
                    <tr>
                        <td>
                            <Label For="Title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
                        </td>
                        <td>
                            <input id="Title" class="form-control" @bind="@_title" />
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <Label For="Theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
                        </td>
                        <td>
                            <select id="Theme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
                                @foreach (var theme in _themes)
                                {
                                    <option value="@theme.TypeName">@theme.Name</option>
                                }
                            </select>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <Label For="defaultContainer" HelpText="Select the default container for the page" ResourceKey="DefaultContainer">Default Container: </Label>
                        </td>
                        <td>
                            <select id="defaultContainer" class="form-control" @bind="@_containertype">
                                <option value="-">&lt;@Localizer["Select Container"]&gt;</option>
                                @foreach (var container in _containers)
                                {
                                    <option value="@container.TypeName">@container.Name</option>
                                }
                            </select>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <Label For="Icon" HelpText="Optionally provide an icon class name for this page which will be displayed in the site navigation" ResourceKey="Icon">Icon: </Label>
                        </td>
                        <td>
                            <input id="Icon" class="form-control" @bind="@_icon" />
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <Label For="Personalizable" HelpText="Select whether you would like users to be able to personalize this page with their own content" ResourceKey="Personalizable">Personalizable? </Label>
                        </td>
                        <td>
                            <select id="Personalizable" class="form-control" @bind="@_ispersonalizable">
                                <option value="True">@Localizer["Yes"]</option>
                                <option value="False">@Localizer["No"]</option>
                            </select>
                        </td>
                    </tr>
                </table>
            </Section>
            <br /><br />
            <AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
        }
    </TabPanel>
    <TabPanel Name="Permissions" ResourceKey="Permissions">
        @if (_permissions != null)
        {
            <table class="table table-borderless">
                <tr>
                    <td>
                        <PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
                    </td>
                </tr>
            </table>
        }
    </TabPanel>
    @if (_themeSettingsType != null)
    {
        <TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
            @ThemeSettingsComponent
        </TabPanel>
    }
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SavePage">@Localizer["Save"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@Localizer["Cancel"]</button>

@code {
    public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;

    private List<Theme> _themeList;
    private List<ThemeControl> _themes = new List<ThemeControl>();
    private List<ThemeControl> _containers = new List<ThemeControl>();
    private List<Page> _pageList;
    private int _pageId;
    private string _name;
    private string _title;
    private string _path;
    private string _currentparentid;
    private string _parentid;
    private string _insert = "=";
    private List<Page> _children;
    private int _childid = -1;
    private string _isnavigation;
    private string _url;
    private string _ispersonalizable;
    private string _themetype;
    private string _containertype = "-";
    private string _icon;
    private string _permissions = null;
    private string _createdby;
    private DateTime _createdon;
    private string _modifiedby;
    private DateTime _modifiedon;
    private string _deletedby;
    private DateTime? _deletedon;
    private PermissionGrid _permissionGrid;
    private Type _themeSettingsType;
    private object _themeSettings;
    private RenderFragment ThemeSettingsComponent { get; set; }
    private bool _refresh = false;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            _pageList = PageState.Pages;
            _children = PageState.Pages.Where(item => item.ParentId == null).ToList();

            _themeList = await ThemeService.GetThemesAsync();
            _themes = ThemeService.GetThemeControls(_themeList);

            _pageId = Int32.Parse(PageState.QueryString["id"]);
            var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
            if (page != null)
            {
                _name = page.Name;
                _title = page.Title;
                _path = page.Path;

                if (_path.Contains("/"))
                {
                    _path = _path.Substring(_path.LastIndexOf("/") + 1);
                }

                if (page.ParentId == null)
                {
                    _parentid = string.Empty;
                }
                else
                {
                    _parentid = page.ParentId.ToString();
                }

                _currentparentid = _parentid;
                _isnavigation = page.IsNavigation.ToString();
                _url = page.Url;
                _ispersonalizable = page.IsPersonalizable.ToString();
                _themetype = page.ThemeType;
                if (string.IsNullOrEmpty(_themetype))
                {
                    _themetype = PageState.Site.DefaultThemeType;
                }
                _containers = ThemeService.GetContainerControls(_themeList, _themetype);
                _containertype = page.DefaultContainerType;
                if (string.IsNullOrEmpty(_containertype))
                {
                    _containertype = PageState.Site.DefaultContainerType;
                }
                _icon = page.Icon;
                _permissions = page.Permissions;
                _createdby = page.CreatedBy;
                _createdon = page.CreatedOn;
                _modifiedby = page.ModifiedBy;
                _modifiedon = page.ModifiedOn;
                _deletedby = page.DeletedBy;
                _deletedon = page.DeletedOn;

                ThemeSettings();
            }
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading Page {PageId} {Error}", _pageId, ex.Message);
            AddModuleMessage(Localizer["Error Loading Page"], MessageType.Error);
        }
    }

    private async void ParentChanged(ChangeEventArgs e)
    {
        try
        {
            _parentid = (string)e.Value;
            _children = new List<Page>();
            if (_parentid == "-1")
            {
                foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
                {
                    if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
                    {
                        _children.Add(p);
                    }
                }
            }
            else
            {
                foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
                {
                    if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
                    {
                        _children.Add(p);
                    }
                }
            }
            if (_parentid == _currentparentid)
            {
                _insert = "=";
            }
            else
            {
                _insert = ">>";
            }
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
            AddModuleMessage(Localizer["Error Loading Child Pages For Parent"], MessageType.Error);
        }
    }

    private async void ThemeChanged(ChangeEventArgs e)
    {
        try
        {
            _themetype = (string)e.Value;
            _containers = ThemeService.GetContainerControls(_themeList, _themetype);
            _containertype = "-";
            ThemeSettings();
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
            AddModuleMessage(Localizer["Error Loading Pane Layouts For Theme"], MessageType.Error);
        }
    }

    private void ThemeSettings()
    {
        _themeSettingsType = null;
        var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
        if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
        {
            _themeSettingsType = Type.GetType(theme.ThemeSettingsType);
            if (_themeSettingsType != null)
            {
                ThemeSettingsComponent = builder =>
                {
                    builder.OpenComponent(0, _themeSettingsType);
                    builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
                    builder.CloseComponent();
                };
            }
            _refresh = true;
        }
    }

    private async Task SavePage()
    {
        Page page = null;
        try
        {
            if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && _containertype != "-")
            {
                page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
                string currentPath = page.Path;

                page.Name = _name;
                page.Title = _title;
                if (_path == "" && _name.ToLower() != "home")
                    if (_path == string.Empty && _name.ToLower() != "home")
                    {
                        _path = _name;
                    }
                if (_path.Contains("/"))
                {
                    _path = _path.Substring(_path.LastIndexOf("/") + 1);
                }
                if (string.IsNullOrEmpty(_parentid) || _parentid == "-1")
                {
                    page.ParentId = null;
                    page.Path = Utilities.GetFriendlyUrl(_path);
                }
                else
                {
                    page.ParentId = Int32.Parse(_parentid);
                    Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
                    if (parent.Path == string.Empty)
                    {
                        page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
                    }
                    else
                    {
                        page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
                    }
                }

                if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList))
                {
                    AddModuleMessage(Localizer["A page with path {0} already exists for the selected parent page. The page path needs to be unique for the selected parent.", _path], MessageType.Warning);
                    return;
                }

                if (_insert != "=")
                {
                    Page child;
                    switch (_insert)
                    {
                        case "<<":
                            page.Order = 0;
                            break;
                        case "<":
                            child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
                            if (child != null) page.Order = child.Order - 1;
                            break;
                        case ">":
                            child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
                            if (child != null) page.Order = child.Order + 1;
                            break;
                        case ">>":
                            page.Order = int.MaxValue;
                            break;
                    }
                }
                page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
                page.Url = _url;
                page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
                if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
                {
                    page.ThemeType = string.Empty;
                }
                page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
                if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
                {
                    page.DefaultContainerType = string.Empty;
                }
                page.Icon = _icon ?? string.Empty;
                page.Permissions = _permissionGrid.GetPermissions();
                page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
                page.UserId = null;

                page = await PageService.UpdatePageAsync(page);
                await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
                if (_currentparentid == string.Empty)
                {
                    await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, null);
                }
                else
                {
                    await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, int.Parse(_currentparentid));
                }

                // update child paths
                if (_parentid != _currentparentid)
                {
                    foreach (Page p in PageState.Pages.Where(item => item.Path.StartsWith(currentPath)))
                    {
                        p.Path = p.Path.Replace(currentPath, page.Path);
                        await PageService.UpdatePageAsync(p);
                    }
                }

                if (_themeSettingsType != null && _themeSettings is ISettingsControl themeSettingsControl)
                {
                    await themeSettingsControl.UpdateSettings();
                }

                await logger.LogInformation("Page Saved {Page}", page);
                if (PageState.QueryString.ContainsKey("cp"))
                {
                    NavigationManager.NavigateTo(NavigateUrl(PageState.Pages.First(item => item.PageId == int.Parse(PageState.QueryString["cp"])).Path));
                }
                else
                {
                    NavigationManager.NavigateTo(NavigateUrl(page.Path));
                }
            }
            else
            {
                AddModuleMessage(Localizer["You Must Provide Page Name, Theme, and Container"], MessageType.Warning);
            }
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message);
            AddModuleMessage(Localizer["Error Saving Page"], MessageType.Error);
        }
    }

    private void Cancel()
    {
        if (PageState.QueryString.ContainsKey("cp"))
        {
            NavigationManager.NavigateTo(NavigateUrl(PageState.Pages.First(item => item.PageId == int.Parse(PageState.QueryString["cp"])).Path));
        }
        else
        {
            NavigationManager.NavigateTo(NavigateUrl());
        }
    }

    private static bool PagePathIsUnique(string pagePath, int siteId, int pageId, List<Page> existingPages)
    {
        return !existingPages.Any(page => page.SiteId == siteId && page.Path == pagePath && page.PageId != pageId);
    }
}
