@namespace Oqtane.Modules.Admin.Sites
@using Oqtane.Interfaces
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ITenantService TenantService
@inject IAliasService AliasService
@inject ISiteService SiteService
@inject IThemeService  ThemeService
@inject ISiteTemplateService SiteTemplateService
@inject IUserService UserService
@inject IInstallationService InstallationService
@inject IStringLocalizer<Add> Localizer
@inject IEnumerable<IOqtaneDatabase> Databases

@if (_tenants == null)
{
    <p><em>@Localizer["Loading..."]</em></p>
}
else
{
<table class="table table-borderless">
    <tr>
        <td>
            <Label For="name" HelpText="Enter the name of the site" ResourceKey="Name">Site Name: </Label>
        </td>
        <td>
            <input id="name" class="form-control" @bind="@_name" />
        </td>
    </tr>
    <tr>
        <td>
            <Label For="alias" HelpText="Enter the alias for the server" ResourceKey="Aliases">Aliases: </Label>
        </td>
        <td>
            <textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
        </td>
    </tr>
    <tr>
        <td>
            <Label For="defaultTheme" HelpText="Select the default theme for the website" ResourceKey="DefaultTheme">Default Theme: </Label>
        </td>
        <td>
            <select id="defaultTheme" class="form-control" @onchange="(e => ThemeChanged(e))">
                <option value="-">&lt;@Localizer["Select Theme"]&gt;</option>
                @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 site" 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="adminContainer" HelpText="Select the admin container for the site" ResourceKey="AdminContainer">Admin Container: </Label>
        </td>
        <td>
            <select id="adminContainer" class="form-control" @bind="@_admincontainertype">
                <option value="-">&lt;@Localizer["Select Container"]&gt;</option>
                <option value="">&lt;@Localizer["Default Admin Container"]&gt;</option>
                @foreach (var container in _containers)
                {
                    <option value="@container.TypeName">@container.Name</option>
                }
            </select>
        </td>
    </tr>
    <tr>
        <td>
            <Label For="siteTemplate" HelpText="Select the site template" ResourceKey="SiteTemplate">Site Template: </Label>
        </td>
        <td>
            <select id="siteTemplate" class="form-control" @bind="@_sitetemplatetype">
                <option value="-">&lt;@Localizer["Select Site Template"]&gt;</option>
                @foreach (SiteTemplate siteTemplate in _siteTemplates)
                {
                    <option value="@siteTemplate.TypeName">@siteTemplate.Name</option>
                }
            </select>
        </td>
    </tr>
    <tr>
        <td>
            <Label For="tenant" HelpText="Select the tenant for the site" ResourceKey="Tenant">Tenant: </Label>
        </td>
        <td>
            <select id="tenant" class="form-control" @onchange="(e => TenantChanged(e))">
                <option value="-">&lt;@Localizer["Select Tenant"]&gt;</option>
                <option value="+">&lt;@Localizer["Create New Tenant"]&gt;</option>
                @foreach (Tenant tenant in _tenants)
                {
                    <option value="@tenant.TenantId">@tenant.Name</option>
                }
            </select>
        </td>
    </tr>
    @if (_tenantid == "+")
    {
        <tr>
            <td colspan="2">
                <hr class="app-rule" />
            </td>
        </tr>
        <tr>
            <td>
                <Label For="name" HelpText="Enter the name for the tenant" ResourceKey="TenantName">Tenant Name: </Label>
            </td>
            <td>
                <input id="name" class="form-control" @bind="@_tenantName" />
            </td>
        </tr>
        <tr>
            <td>
                <Label For="databaseType" HelpText="Select the database type for the tenant" ResourceKey="DatabaseType">Database Type: </Label>
            </td>
            <td>
                <select id="databaseType" class="custom-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))">
                    @foreach (var database in _databases)
                    {
                        <option value="@database.Name">@Localizer[@database.FriendlyName]</option>
                    }
                </select>
            </td>
        </tr>
        if (_databaseConfigType != null)
        {
            @DatabaseConfigComponent;
        }
        <tr>
            <td>
                <Label For="hostUsername" HelpText="Enter the username of the host for this site" ResourceKey="HostUsername">Host Username:</Label>
            </td>
            <td>
                <input id="hostUsername" class="form-control" @bind="@_hostUserName" readonly />
            </td>
        </tr>
        <tr>
            <td>
                <Label For="hostPassword" HelpText="Enter the password for the host of this site" ResourceKey="HostPassword">Host Password:</Label>
            </td>
            <td>
                <input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" />
            </td>
        </tr>
    }
</table>
    <button type="button" class="btn btn-success" @onclick="SaveSite">@Localizer["Save"]</button>
    <NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
}

@code {
    private IList<Database> _databases;
    private string _databaseName = "LocalDB";
    private Type _databaseConfigType;
    private object _databaseConfig;
    private RenderFragment DatabaseConfigComponent { get; set; }


    private List<Theme> _themeList;
    private List<ThemeControl> _themes = new List<ThemeControl>();
    private List<ThemeControl> _containers = new List<ThemeControl>();
    private List<SiteTemplate> _siteTemplates;
    private List<Tenant> _tenants;
    private string _tenantid = "-";

    private string _tenantName = string.Empty;
    
    private string _hostUserName = UserNames.Host;
    private string _hostpassword = string.Empty;

    private string _name = string.Empty;
    private string _urls = string.Empty;
    private string _themetype = "-";
    private string _containertype = "-";
    private string _admincontainertype = "";
    private string _sitetemplatetype = "-";

    public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;

    protected override async Task OnInitializedAsync()
    {
        _tenants = await TenantService.GetTenantsAsync();
        _urls = PageState.Alias.Name;
        _themeList = await ThemeService.GetThemesAsync();
        _themes = ThemeService.GetThemeControls(_themeList);
        _siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
        
        _databases = new List<Database>
        {
            new()
            {
                Name = "LocalDB",
                FriendlyName = "Local Database",
                Type = "Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client"
            },
            new()
            {
                Name = "SqlServer",
                FriendlyName = "SQL Server",
                Type = "Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client"
            },
            new()
            {
                Name = "Sqlite",
                FriendlyName = "Sqlite",
                Type = "Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client"
            },
            new()
            {
                Name = "MySQL",
                FriendlyName = "MySQL",
                Type = "Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client"
            },
            new()
            {
                Name = "PostgreSQL",
                FriendlyName = "PostgreSQL",
                Type = "Oqtane.Installer.Controls.PostGreSQLConfig, Oqtane.Client"
            }
        };
        
        LoadDatabaseConfigComponent();
    }
    
    private void DatabaseChanged(ChangeEventArgs eventArgs)
    {
        try
        {
            _databaseName = (string)eventArgs.Value;

            LoadDatabaseConfigComponent();
        }
        catch (Exception exception)
        {
            AddModuleMessage(Localizer["Error loading Database Configuration Control"], MessageType.Error);
        }
    }

    private void LoadDatabaseConfigComponent()
    {
        var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
        if (database != null)
        {
            _databaseConfigType = Type.GetType(database.Type);
            DatabaseConfigComponent = builder =>
            {
                builder.OpenComponent(0, _databaseConfigType);
                builder.AddAttribute(1, "IsInstaller", false);
                builder.AddComponentReferenceCapture(2, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
                builder.CloseComponent();
            };
        }
    }

    private void TenantChanged(ChangeEventArgs e)
    {
        _tenantid = (string)e.Value;
        if (string.IsNullOrEmpty(_tenantName))
        {
            _tenantName = _name;
        }
        StateHasChanged();
    }

    private async void ThemeChanged(ChangeEventArgs e)
    {
        try
        {
            _themetype = (string)e.Value;
            if (_themetype != "-")
            {
                _containers = ThemeService.GetContainerControls(_themeList, _themetype);
            }
            else
            {
                _containers = new List<ThemeControl>();
            }
            _containertype = "-";
            _admincontainertype = "";
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
            AddModuleMessage(Localizer["Error Loading Containers For Theme"], MessageType.Error);
        }
    }

    private async Task SaveSite()
    {
        if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
        {
            var duplicates = new List<string>();
            var aliases = await AliasService.GetAliasesAsync();
            foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (aliases.Exists(item => item.Name == name))
                {
                    duplicates.Add(name);
                }
            }

            if (duplicates.Count == 0)
            {
                InstallConfig config = new InstallConfig();

                if (_tenantid == "+")
                {
                    if (!string.IsNullOrEmpty(_tenantName) && _tenants.FirstOrDefault(item => item.Name == _tenantName) == null)
                    {
                        // validate host credentials
                        var user = new User();
                        user.SiteId = PageState.Site.SiteId;
                        user.Username = UserNames.Host;
                        user.Password = _hostpassword;
                        user = await UserService.LoginUserAsync(user, false, false);
                        if (user.IsAuthenticated)
                        {
                            var connectionString = String.Empty;
                            if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
                            {
                                connectionString = databaseConfigControl.GetConnectionString();
                            }
                            if (connectionString != "")
                            {
                                config.DatabaseType = _databaseName;
                                config.ConnectionString = connectionString;
                                config.HostPassword = _hostpassword;
                                config.HostEmail = user.Email;
                                config.HostName = user.DisplayName;
                                config.TenantName = _tenantName;
                                config.IsNewTenant = true;
                            }
                            else
                            {
                                AddModuleMessage(Localizer["You Must Specify A Server And Database"], MessageType.Error);
                            }
                        }
                        else
                        {
                            AddModuleMessage(Localizer["Invalid Host Password"], MessageType.Error);
                        }
                    }
                    else
                    {
                        AddModuleMessage(Localizer["Tenant Name Is Missing Or Already Exists"], MessageType.Error);
                    }
                }
                else
                {
                    var tenant = _tenants.FirstOrDefault(item => item.TenantId == int.Parse(_tenantid));
                    if (tenant != null)
                    {
                        config.TenantName = tenant.Name;
                        config.ConnectionString= tenant.DBConnectionString;
                        config.IsNewTenant = false;
                    }
                }

                if  (!string.IsNullOrEmpty(config.TenantName))
                {
                    config.SiteName = _name;
                    config.Aliases = _urls.Replace("\n", ",");
                    config.DefaultTheme = _themetype;
                    config.DefaultContainer = _containertype;
                    config.DefaultAdminContainer = _admincontainertype;
                    config.SiteTemplate = _sitetemplatetype;

                    ShowProgressIndicator();

                    var installation = await InstallationService.Install(config);
                    if (installation.Success)
                    {
                        var aliasname = config.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
                        var uri = new Uri(NavigationManager.Uri);
                        NavigationManager.NavigateTo(uri.Scheme + "://" + aliasname, true);
                    }
                    else
                    {
                        await logger.LogError("Error Creating Site {Error}", installation.Message);
                        AddModuleMessage(installation.Message, MessageType.Error);
                    }
                }
            }
            else
            {
                AddModuleMessage(Localizer["{0} Already Used For Another Site", string.Join(", ", duplicates.ToArray())], MessageType.Warning);
            }
        }
        else
        {
            AddModuleMessage(Localizer["You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template"], MessageType.Warning);
        }
    }
}
