@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@using System.Globalization
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
@inject ILanguageService LanguageService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<Edit> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@inject IPageModuleService PageModuleService
@inject IModuleService ModuleService
@inject IPageService PageService

@if (_initialized)
{
	<TabStrip>
        <TabPanel Name="Definition" ResourceKey="Definition" Heading="Definition">
			<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
				<div class="container">
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
						<div class="col-sm-9">
							<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="description" HelpText="The description of the module" ResourceKey="Description">Description: </Label>
						<div class="col-sm-9">
							<textarea id="description" class="form-control" @bind="@_description" rows="2" maxlength="2000" required></textarea>
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
						<div class="col-sm-9">
							<input id="categories" class="form-control" @bind="@_categories" maxlength="200" />
						</div>
					</div>
                    <div class="row mb-1 align-items-center">
                        <Label Class="col-sm-3" For="isenabled" HelpText="Is module enabled for this site?" ResourceKey="IsEnabled">Enabled? </Label>
                        <div class="col-sm-9">
                            <select id="isenabled" class="form-select" @bind="@_isenabled" required>
                                <option value="True">@SharedLocalizer["Yes"]</option>
                                <option value="False">@SharedLocalizer["No"]</option>
                            </select>
                        </div>
                    </div>
                </div>
			</form>
			<Section Name="Information" ResourceKey="Information">
				<div class="container">
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="moduledefinitionname" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
						<div class="col-sm-9">
							<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="version" HelpText="The version of the module" ResourceKey="Version">Version: </Label>
						<div class="col-sm-9">
							<input id="version" class="form-control" @bind="@_version" disabled />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification." ResourceKey="PackageName">Package Name: </Label>
						<div class="col-sm-9">
                            <input id="packagename" class="form-control" @bind="@_packagename" disabled />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the module" ResourceKey="Owner">Owner: </Label>
						<div class="col-sm-9">
							<input id="owner" class="form-control" @bind="@_owner" disabled />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="url" HelpText="The reference url of the module" ResourceKey="ReferenceUrl">Reference Url: </Label>
						<div class="col-sm-9">
							<input id="url" class="form-control" @bind="@_url" disabled />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="contact" HelpText="The contact for the module" ResourceKey="Contact">Contact: </Label>
						<div class="col-sm-9">
							<input id="contact" class="form-control" @bind="@_contact" disabled />
						</div>
					</div>
					<div class="row mb-1 align-items-center">
						<Label Class="col-sm-3" For="license" HelpText="The module license terms" ResourceKey="License">License: </Label>
						<div class="col-sm-9">
                            @if (_license.StartsWith("http") || _license.StartsWith("/") || _license.StartsWith("~"))
                            {
                                <a href="@_license.Replace("~", PageState?.Alias.BaseUrl + "/Modules/" + Utilities.GetTypeName(_moduledefinitionname))" class="btn btn-info" style="text-decoration: none !important" target="_new">@Localizer["View License"]</a>
                            }
                            else
                            {
                                <textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
                            }
						</div>
					</div>
				</div>
			</Section>
			<br />
			<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
			<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
			<br />
			<br />
			<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
		</TabPanel>
		<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
			<div class="container">
				<div class="row mb-1 align-items-center">
					<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" PermissionList="@_permissions" @ref="_permissionGrid" />
				</div>
			</div>
			<br />
			<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
			<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
		</TabPanel>
        <TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
                <Pager Items="@_pagesWithModules" RowClass="align-middle">
                <Header>
                <th style="width: 1px;">&nbsp;</th>
                <th>@SharedLocalizer["Name"]</th>
                </Header>
                <Row>
                    <td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
                    <td>@(string.IsNullOrEmpty(context.Title) ? @context.Name : @context.Title )</td>
                </Row>
                </Pager>
        </TabPanel>
        <TabPanel Name="Translations" ResourceKey="Translations" Heading="Translations">
			@if (_languages != null && _languages.Count > 0)
			{
                <Pager Items="@_languages">
					<Header>
					<th>@SharedLocalizer["Name"]</th>
					<th>@Localizer["Code"]</th>
					<th style="width: 1px;">@Localizer["Version"]</th>
					<th style="width: 1px;">&nbsp;</th>
					</Header>
					<Row>
						<td>@context.Name</td>
						<td>@context.Code</td>
						<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
						<td>
							@switch (TranslationAvailable(_packagename + "." + context.Code, context.Version))
							{
								case "install":
									<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
									break;
								case "upgrade":
									<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
									break;
							}
						</td>
					</Row>
				</Pager>
			}
			else
			{
				<br />
				<div class="mx-auto text-center">
					@if (string.IsNullOrEmpty(_packagename))
					{
						@Localizer["Search.PackageNameMissing"]
					}
					else
					{
						@Localizer["Search.NoResults"]
					}
				</div>
				<br />
			}
		</TabPanel>
	</TabStrip>

	@if (_package != null)
	{
		<div class="app-actiondialog">
			<div class="modal" tabindex="-1" role="dialog">
				<div class="modal-dialog">
					<div class="modal-content">
						<div class="modal-header">
							<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
							<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
						</div>
						<div class="modal-body">
							<p style="height: 200px; overflow-y: scroll;">
								<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
								@SharedLocalizer["Search.By"]:&nbsp;&nbsp;<strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
								@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
								<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"]&nbsp;&nbsp;|&nbsp;&nbsp;
								@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong>&nbsp;&nbsp;|&nbsp;&nbsp;
								@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
								@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? "&nbsp;&nbsp;|&nbsp;&nbsp;" + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
								<br /><br />
								@if (!string.IsNullOrEmpty(_package.License))
								{
									@((MarkupString)_package.License.Replace("\n", "<br />"))
								}
								else
								{
									@SharedLocalizer["License Not Specified"]
								}
							</p>
						</div>
						<div class="modal-footer">
							<button type="button" class="btn btn-success" @onclick="DownloadTranslation">@SharedLocalizer["Accept"]</button>
							<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
						</div>
					</div>
				</div>
			</div>
		</div>
	}
}

@code {
    private bool _initialized = false;
    private ElementReference form;
    private bool validated = false;
    private int _moduleDefinitionId;
    private string _name;
    private string _description = "";
    private string _categories;
    private string _isenabled;
    private string _moduledefinitionname = "";
    private string _version;
    private string _packagename = "";
    private string _owner = "";
    private string _url = "";
    private string _contact = "";
    private string _license = "";
    private List<Permission> _permissions = null;
    private string _createdby;
    private DateTime _createdon;
    private string _modifiedby;
    private DateTime _modifiedon;
    private List<Page> _pagesWithModules;

#pragma warning disable 649
    private PermissionGrid _permissionGrid;
#pragma warning restore 649

    private List<Package> _packages;
    private List<Language> _languages;
    private Package _package;

    public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            _moduleDefinitionId = Int32.Parse(PageState.QueryString["id"]);
            var moduleDefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
            if (moduleDefinition != null)
            {
                _name = moduleDefinition.Name;
                _description = moduleDefinition.Description;
                _categories = moduleDefinition.Categories;
                _isenabled = moduleDefinition.IsEnabled.ToString();
                _moduledefinitionname = moduleDefinition.ModuleDefinitionName;
                _version = moduleDefinition.Version;
                _packagename = moduleDefinition.PackageName;
                _owner = moduleDefinition.Owner;
                _url = moduleDefinition.Url;
                _contact = moduleDefinition.Contact;
                _license = moduleDefinition.License;
                _permissions = moduleDefinition.PermissionList;
                _createdby = moduleDefinition.CreatedBy;
                _createdon = moduleDefinition.CreatedOn;
                _modifiedby = moduleDefinition.ModifiedBy;
                _modifiedon = moduleDefinition.ModifiedOn;

                if (!string.IsNullOrEmpty(_packagename))
                {
                    _packages = await PackageService.GetPackagesAsync("translation", "", "", _packagename);
                    _languages = await LanguageService.GetLanguagesAsync(-1, _packagename);
                    foreach (var package in _packages)
                    {
                        var code = package.PackageId.Split('.').Last();
                        if (!_languages.Any(item => item.Code == code))
                        {
                            _languages.Add(new Language { Code = code, Name = CultureInfo.GetCultureInfo(code).DisplayName, Version = package.Version, IsDefault = true });
                        }
                    }
                    _languages = _languages.OrderBy(item => item.Name).ToList();
                }

                // get distinct pages where module exists
                var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
                var distinctPageIds = modules
                    .Where(md => md.ModuleDefinition?.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false)
                    .Select(md => md.PageId)
                    .Distinct();

                // retrieve the pages which contain the module
                var pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
                _pagesWithModules = pages
                    .Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false)
                    .ToList();

                _initialized = true;
            }
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
            AddModuleMessage(Localizer["Error.Module.Load"], MessageType.Error);
        }
    }

    private async Task SaveModuleDefinition()
    {
        validated = true;
        var interop = new Interop(JSRuntime);
        if (await interop.FormValid(form))
        {
            try
            {
                var moduleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
                if (!moduleDefinitions.Any(item => item.Name.ToLower() == _name.ToLower() && item.ModuleDefinitionId != _moduleDefinitionId))
                {
                    var moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
                    if (moduledefinition.Name != _name)
                    {
                        moduledefinition.Name = _name;
                    }
                    if (moduledefinition.Description != _description)
                    {
                        moduledefinition.Description = _description;
                    }
                    if (moduledefinition.Categories != _categories)
                    {
                        moduledefinition.Categories = _categories;
                    }
                    moduledefinition.IsEnabled = (_isenabled == null ? true : bool.Parse(_isenabled));
                    moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
                    await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
                    await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
                    NavigationManager.NavigateTo(NavigateUrl());
                }
                else
                {
                    AddModuleMessage(Localizer["Message.DuplicateName"], MessageType.Warning);
                }
            }
            catch (Exception ex)
            {
                await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
                AddModuleMessage(Localizer["Error.Module.Save"], MessageType.Error);
            }
        }
        else
        {
            AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
        }
    }

    private void HideModal()
    {
        _package = null;
        StateHasChanged();
    }

    private string TranslationAvailable(string packagename, string version)
    {
        if (_packages != null)
        {
            var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
            if (package != null)
            {
                if (string.IsNullOrEmpty(version))
                {
                    return "install";
                }
                else
                {
                    if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
                    {
                        return "upgrade";
                    }
                }
            }
        }
        return "";
    }

    private async Task GetPackage(string packagename)
    {
        var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
        try
        {
            _package = await PackageService.GetPackageAsync(packagename, version, false);
            if (_package != null)
            {
                StateHasChanged();
            }
            else
            {
                await logger.LogError("Error Getting Package {PackageId} {Version}", packagename, version);
                AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
            }
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packagename, version);
            AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
        }
    }

    private async Task DownloadTranslation()
    {
        try
        {
            await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version);
            await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
            AddModuleMessage(string.Format(Localizer["Success.Translation.Download"], NavigateUrl("admin/system")), MessageType.Success);
            _package = null;
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
            AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
        }
    }

    private string Browse(Page page) => string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
}
