@namespace Oqtane.Modules.Admin.UserProfile
@using System.Net
@using System.Text.RegularExpressions;
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IProfileService ProfileService
@inject ISettingService SettingService
@inject INotificationService NotificationService
@inject IFileService FileService
@inject IFolderService FolderService
@inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer

@if (_initialized)
{
    @if (PageState.User != null && photo != null)
    {
        <img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
    }
    else
    {
        <br />
    }
    <TabStrip>
        <TabPanel Name="Identity" ResourceKey="Identity">
            <ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
            <div class="container">
                <div class="row mb-1 align-items-center">
                    <Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified." ResourceKey="Username"></Label>
                    <div class="col-sm-9">
                        <input id="username" class="form-control" @bind="@username" readonly />
                    </div>
                </div>
                <div class="row mb-1 align-items-center">
                    <Label Class="col-sm-3" For="password" HelpText="If you wish to change your password you can enter it here. Please choose a sufficiently secure password." ResourceKey="Password"></Label>
                    <div class="col-sm-9">
                        <div class="input-group">
                            <input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
                            <button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
                        </div>
                    </div>
                </div>
                <div class="row mb-1 align-items-center">
                    <Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
                    <div class="col-sm-9">
                        <div class="input-group">
                            <input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
                            <button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
                        </div>
                    </div>
                </div>
                @if (allowtwofactor)
                {
                    <div class="row mb-1 align-items-center">
                        <Label Class="col-sm-3" For="twofactor" HelpText="Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in." ResourceKey="TwoFactor"></Label>
                        <div class="col-sm-9">
                            <select id="twofactor" class="form-select" @bind="@twofactor" required>
                                <option value="True">@SharedLocalizer["Yes"]</option>
                                <option value="False">@SharedLocalizer["No"]</option>
                            </select>
                        </div>
                    </div>
                }
                <div class="row mb-1 align-items-center">
                    <Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
                    <div class="col-sm-9">
                        <input id="email" class="form-control" @bind="@email" />
                    </div>
                </div>
                <div class="row mb-1 align-items-center">
                    <Label Class="col-sm-3" For="displayname" HelpText="Your full name" ResourceKey="DisplayName"></Label>
                    <div class="col-sm-9">
                        <input id="displayname" class="form-control" @bind="@displayname" />
                    </div>
                </div>
                <div class="row mb-1 align-items-center">
                    <Label Class="col-sm-3" For="@photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
                    <div class="col-sm-9">
                        <FileManager FileId="@photofileid" Filter="@PageState.Site.ImageFiles" ShowFolders="false" ShowFiles="true" UploadMultiple="false" FolderId="@folderid" @ref="filemanager" />
                    </div>
                </div>
            </div>
            <br />
            <button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
            <button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
        </TabPanel>
        <TabPanel Name="Profile" ResourceKey="Profile">
            <div class="container">
                <div class="row mb-1 align-items-center">
                    @foreach (Profile profile in profiles)
                    {
                        var p = profile;
                        if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
                        {
                            if (p.Category != category)
                            {
                                <div class="col text-center pb-2">
                                    @p.Category
                                </div>
                                category = p.Category;
                            }
                            <div class="row mb-1 align-items-center">
                                <Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
                                    <div class="col-sm-9">
                                    @if (!string.IsNullOrEmpty(p.Options))
                                    {
                                        @if (!string.IsNullOrEmpty(p.Autocomplete))
                                        {
                                            <select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete">
                                                @foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                                                {
                                                    @if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
                                                    {
                                                        <option value="@option" selected>@option</option>
                                                    }
                                                    else
                                                    {
                                                        <option value="@option">@option</option>
                                                    }
                                                }
                                            </select>
                                        }
                                        else
                                        {
                                            <select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
                                                @foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                                                {
                                                    @if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
                                                    {
                                                        <option value="@option" selected>@option</option>
                                                    }
                                                    else
                                                    {
                                                        <option value="@option">@option</option>
                                                    }
                                                }
                                            </select>
                                        }
                                    }
                                    else
                                    {
                                        @if (p.Rows == 1)
                                        {
                                            if (!string.IsNullOrEmpty(p.Autocomplete))
                                            {
                                                @if (p.IsRequired)
                                                {
                                                    <input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete" />
                                                }
                                                else
                                                {
                                                    <input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete" />
                                                }
                                            }
                                            else
                                            {
                                                @if (p.IsRequired)
                                                {
                                                    <input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
                                                }
                                                else
                                                {
                                                    <input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (!string.IsNullOrEmpty(p.Autocomplete))
                                            {
                                                @if (p.IsRequired)
                                                {
                                                    <textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"></textarea>
                                                }
                                                else
                                                {
                                                    <textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" autocomplete="@p.Autocomplete"></textarea>
                                                }
                                            }
                                            else
                                            {
                                                @if (p.IsRequired)
                                                {
                                                    <textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
                                                }
                                                else
                                                {
                                                    <textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
                                                }
                                            }
                                        }
                                    }
                                </div>
                            </div>
                        }
                    }
                </div>
            </div>
            <button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
            <button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
        </TabPanel>
        <TabPanel Name="Notifications" ResourceKey="Notifications">
            <ActionLink Action="Add" Text="Send Notification" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="SendNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" />
            <br />
            <br />
            <select class="form-select" @onchange="(e => FilterChanged(e))">
                <option value="to">@Localizer["Inbox"]</option>
                <option value="from">@Localizer["Items.Sent"]</option>
            </select>
            <br />
            @if (filter == "to")
            {
                @if (notifications.Any())
                {
                    <Pager Items="@notifications">
                        <Header>
                        <th style="width: 1px;">&nbsp;</th>
                        <th style="width: 1px;">&nbsp;</th>
                        <th>@Localizer["From"]</th>
                        <th>@Localizer["Subject"]</th>
                        <th>@Localizer["Received"]</th>
                        </Header>
                        <Row>
                            <td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
                            <td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>

                            @if (context.IsRead)
                            {
                                <td>@context.FromDisplayName</td>
                                <td>@context.Subject</td>
                                <td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
                            }
                            else
                            {
                                <td><b>@context.FromDisplayName</b></td>
                                <td><b>@context.Subject</b></td>
                                <td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
                            }
                        </Row>
                        <Detail>
                            <td colspan="2"></td>
                            <td colspan="3">
                                @{
                                    string input = "___";
                                    if (context.Body.Contains(input))
                                    {
                                        context.Body = context.Body.Split(input)[0];
                                        context.Body = context.Body.Replace("\n", "");
                                        context.Body = context.Body.Replace("\r", "");
                                    }
                                    notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
                                }
                                @if (context.IsRead)
                                {
                                    @notificationSummary
                                }
                                else
                                {
                                    <b>@notificationSummary</b>
                                }
                            </td>
                        </Detail>
                    </Pager>
                    <br />
                    <ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
                }
                else
                {
                    <div class="no-notifications-text">
                        @Localizer["NoNotificationsReceived.Text"]
                    </div>
                }
            }
            else
            {
                @if (notifications.Any())
                {
                    <Pager Items="@notifications">
                        <Header>
                        <th style="width: 1px;"></th>
                        <th style="width: 1px;"></th>
                        <th>@Localizer["To"]</th>
                        <th>@Localizer["Subject"]</th>
                        <th>@Localizer["Sent"]</th>
                        </Header>
                        <Row>
                            <td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" ReturnUrl="@NavigateUrl(PageState.Page.Path, "tab=Notifications")" /></td>
                            <td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>

                            @if (context.IsRead)
                            {
                                <td>@context.ToDisplayName</td>
                                <td>@context.Subject</td>
                                <td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
                            }
                            else
                            {
                                <td><b>@context.ToDisplayName</b></td>
                                <td><b>@context.Subject</b></td>
                                <td><b>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</b></td>
                            }

                        </Row>
                        <Detail>
                            <td colspan="2"></td>
                            <td colspan="3">
                                @{
                                    string input = "___";
                                    if (context.Body.Contains(input))
                                    {
                                        context.Body = context.Body.Split(input)[0];
                                        context.Body = context.Body.Replace("\n", "");
                                        context.Body = context.Body.Replace("\r", "");
                                    }
                                    notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
                                }
                                @if (context.IsRead)
                                {
                                    @notificationSummary
                                }
                                else
                                {
                                    <b>@notificationSummary</b>
                                }
                            </td>
                        </Detail>
                    </Pager>
                    <br />
                    <ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
                }
                else
                {
                    <div class="no-notifications-text">
                        @Localizer["NoNotificationsSent.Text"]
                    </div>
                }
            }
        </TabPanel>
    </TabStrip>
    <br />
    <br />
}

@code {
    private bool _initialized = false;
    private string _passwordrequirements;
    private string username = string.Empty;
    private string _password = string.Empty;
    private string _passwordtype = "password";
    private string _togglepassword = string.Empty;
    private string confirm = string.Empty;
    private bool allowtwofactor = false;
    private string twofactor = "False";
    private string email = string.Empty;
    private string displayname = string.Empty;
    private FileManager filemanager;
    private int folderid = -1;
    private int photofileid = -1;
    private File photo = null;
    private string _ImageFiles = string.Empty;
    private List<Profile> profiles;
    private Dictionary<string, string> settings;
    private string category = string.Empty;

    private string filter = "to";
    private List<Notification> notifications;
    private string notificationSummary = string.Empty;

    public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            _passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
            _togglepassword = SharedLocalizer["ShowPassword"];
            allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
            profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);

            if (PageState.User != null)
            {
                username = PageState.User.Username;
                twofactor = PageState.User.TwoFactorRequired.ToString();
                email = PageState.User.Email;
                displayname = PageState.User.DisplayName;

                if (string.IsNullOrEmpty(email))
                {
                    AddModuleMessage(Localizer["Message.User.NoEmail"], MessageType.Warning);
                }

                // get user folder
                var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
                if (folder != null)
                {
                    folderid = folder.FolderId;
                }

                if (PageState.User.PhotoFileId != null)
                {
                    photofileid = PageState.User.PhotoFileId.Value;
                    photo = await FileService.GetFileAsync(photofileid);
                }
                else
                {
                    photofileid = -1;
                    photo = null;
                }

                settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
                var sitesettings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
                _ImageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
                _ImageFiles = (string.IsNullOrEmpty(_ImageFiles)) ? Constants.ImageFiles : _ImageFiles;

                await LoadNotificationsAsync();

                _initialized = true;
            }
            else
            {
                AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
            }
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
            AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
        }
    }

    private async Task LoadNotificationsAsync()
    {
        notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
        notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
    }

    private string GetProfileValue(string SettingName, string DefaultValue)
    {
        string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
        if (value.Contains("]"))
        {
            value = value.Substring(value.IndexOf("]") + 1);
        }
        return value;
    }

    private async Task Save()
    {
        try
        {
            if (username != string.Empty && email != string.Empty)
            {
                if (_password == confirm)
                {
                    if (ValidateProfiles())
                    {
                        var user = PageState.User;
                        user.Username = username;
                        user.Password = _password;
                        user.TwoFactorRequired = bool.Parse(twofactor);
                        user.Email = email;
                        user.DisplayName = (displayname == string.Empty ? username : displayname);
                        user.PhotoFileId = filemanager.GetFileId();
                        if (user.PhotoFileId == -1)
                        {
                            user.PhotoFileId = null;
                        }
                        if (user.PhotoFileId != null)
                        {
                            photofileid = user.PhotoFileId.Value;
                            photo = await FileService.GetFileAsync(photofileid);
                        }
                        else
                        {
                            photofileid = -1;
                            photo = null;
                        }

                        user = await UserService.UpdateUserAsync(user);
                        if (user != null)
                        {
                            await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
                            await logger.LogInformation("User Profile Saved");

                            if (!string.IsNullOrEmpty(PageState.ReturnUrl))
                            {
                                NavigationManager.NavigateTo(PageState.ReturnUrl);
                            }
                            else // legacy behavior
                            {
                                AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
                                StateHasChanged();
                            }
                        }
                        else
                        {
                            AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
                        }
                    }
                }
                else
                {
                    AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
                }
            }
            else
            {
                AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
            }

            await ScrollToPageTop();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Saving User Profile {Error}", ex.Message);
            AddModuleMessage(Localizer["Error.Profile.Save"], MessageType.Error);
        }
    }

    private bool ValidateProfiles()
    {
        foreach (Profile profile in profiles)
        {
            var value = GetProfileValue(profile.Name, string.Empty);
            if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
            {
                settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
            }
            if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
            {
                if (profile.IsRequired && string.IsNullOrEmpty(value))
                {
                    AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
                    return false;
                }
                if (!string.IsNullOrEmpty(profile.Validation))
                {
                    Regex regex = new Regex(profile.Validation);
                    bool valid = regex.Match(value).Success;
                    if (!valid)
                    {
                        AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private void Cancel()
    {
        NavigationManager.NavigateTo(PageState.ReturnUrl);
    }

    private void ProfileChanged(ChangeEventArgs e, string SettingName)
    {
        var value = (string)e.Value;
        settings = SettingService.SetSetting(settings, SettingName, value);
    }

    private async Task Delete(Notification Notification)
    {
        try
        {
            if (!Notification.IsDeleted)
            {
                Notification.IsDeleted = true;
                await NotificationService.UpdateNotificationAsync(Notification);
            }
            else
            {
                await NotificationService.DeleteNotificationAsync(Notification.NotificationId);
            }

            await logger.LogInformation("Notification Deleted {Notification}", Notification);
            await LoadNotificationsAsync();
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Deleting Notification {Notification} {Error}", Notification, ex.Message);
            AddModuleMessage(ex.Message, MessageType.Error);
        }
    }

    private async void FilterChanged(ChangeEventArgs e)
    {
        filter = (string)e.Value;
        await LoadNotificationsAsync();
        StateHasChanged();
    }

    private async Task DeleteAllNotifications()
    {
        try
        {
            ShowProgressIndicator();
            foreach(var Notification in notifications)
            {
                if (!Notification.IsDeleted)
                {
                    Notification.IsDeleted = true;
                    await NotificationService.UpdateNotificationAsync(Notification);
                }
                else
                {
                    await NotificationService.DeleteNotificationAsync(Notification.NotificationId);
                }
                await logger.LogInformation("Notification Deleted {Notification}", Notification);
            }
            await logger.LogInformation("Notifications Permanently Deleted");
            await LoadNotificationsAsync();
            HideProgressIndicator();

            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Deleting Notifications {Error}", ex.Message);
            AddModuleMessage(ex.Message, MessageType.Error);
            HideProgressIndicator();
        }
    }

    private void TogglePassword()
    {
        if (_passwordtype == "password")
        {
            _passwordtype = "text";
            _togglepassword = SharedLocalizer["HidePassword"];
        }
        else
        {
            _passwordtype = "password";
            _togglepassword = SharedLocalizer["ShowPassword"];
        }
    }
}
