<#@ template hostSpecific="true" #>
<#@ assembly name="Microsoft.EntityFrameworkCore" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #>
<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #>
<#@ parameter name="Model" type="Microsoft.EntityFrameworkCore.Metadata.IModel" #>
<#@ parameter name="Options" type="Microsoft.EntityFrameworkCore.Scaffolding.ModelCodeGenerationOptions" #>
<#@ parameter name="NamespaceHint" type="System.String" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="Microsoft.EntityFrameworkCore" #>
<#@ import namespace="Microsoft.EntityFrameworkCore.Design" #>
<#@ import namespace="Microsoft.EntityFrameworkCore.Infrastructure" #>
<#@ import namespace="Microsoft.EntityFrameworkCore.Scaffolding" #>
<#@ import namespace="Microsoft.Extensions.DependencyInjection" #>
<#
    if (!ProductInfo.GetVersion().StartsWith("8.0"))
    {
        Warning("Your templates were created using an older version of Entity Framework. Additional features and bug fixes may be available. See https://aka.ms/efcore-docs-updating-templates for more information.");
    }

    var services = (IServiceProvider)Host;
    var providerCode = services.GetRequiredService<IProviderConfigurationCodeGenerator>();
    var annotationCodeGenerator = services.GetRequiredService<IAnnotationCodeGenerator>();
    var code = services.GetRequiredService<ICSharpHelper>();

    var usings = new List<string>
    {
        "System",
        "System.Collections.Generic",
        "Microsoft.EntityFrameworkCore"
    };

    if (NamespaceHint != Options.ModelNamespace
        && !string.IsNullOrEmpty(Options.ModelNamespace))
    {
        usings.Add(Options.ModelNamespace);
    }

    if (!string.IsNullOrEmpty(NamespaceHint))
    {
#>
namespace <#= NamespaceHint #>;

<#
    }
#>
/// <summary>
/// 云游戏实体类
/// </summary>
public partial class <#= Options.ContextName #> : MultiTenantDbContext//DbContext
{
<#
    if (!Options.SuppressOnConfiguring)
    {
#>
    public <#= Options.ContextName #>() : base(null)
    {
    }

<#
    }
#>
    public <#= Options.ContextName #>(DbContextOptions<<#= Options.ContextName #>> options)
         : base(null, options)
    {
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="tenantInfo"></param>
    public <#= Options.ContextName #>(ITenantInfo tenantInfo) : base(tenantInfo)
    {

    }


    /// <summary>
    /// 
    /// </summary>
    /// <param name="tenantInfo"></param>
    /// <param name="options"></param>
    public <#= Options.ContextName #>(ITenantInfo tenantInfo, DbContextOptions<<#= Options.ContextName #>> options) : base(tenantInfo, options)
    {
    }


<#
    foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType()))
    {
#>
    /// <summary>
    /// <#=entityType.GetComment()??"" #>
    /// </summary>
    public virtual DbSet<<#= entityType.Name #>> <#= entityType.GetDbSetName() #> { get; set; }

<#
    }

    if (!Options.SuppressOnConfiguring)
    {
#>
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
<#
    if (!Options.SuppressConnectionStringWarning)
    {
#>
<#
    }

    var useProviderCall = providerCode.GenerateUseProvider(Options.ConnectionString);
    usings.AddRange(useProviderCall.GetRequiredUsings());
#>
     {  // => optionsBuilder<#= code.Fragment(useProviderCall, indent: 3) #>;
      } 

<#
    }

#>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
<#
    var anyConfiguration = false;

    var modelFluentApiCalls = Model.GetFluentApiCalls(annotationCodeGenerator);
    if (modelFluentApiCalls != null)
    {
        usings.AddRange(modelFluentApiCalls.GetRequiredUsings());
#>
        modelBuilder<#= code.Fragment(modelFluentApiCalls, indent: 3) #>;
<#
        anyConfiguration = true;
    }

    StringBuilder mainEnvironment;
    foreach (var entityType in Model.GetEntityTypes().Where(e => !e.IsSimpleManyToManyJoinEntityType()))
    {
        // Save all previously generated code, and start generating into a new temporary environment
        mainEnvironment = GenerationEnvironment;
        GenerationEnvironment = new StringBuilder();

        if (anyConfiguration)
        {
            WriteLine("");
        }

        var anyEntityTypeConfiguration = false;
#>
        modelBuilder.Entity<<#= entityType.Name #>>(entity =>
        {
<#
        var key = entityType.FindPrimaryKey();
        if (key != null)
        {
            var keyFluentApiCalls = key.GetFluentApiCalls(annotationCodeGenerator);
            if (keyFluentApiCalls != null
                || (!key.IsHandledByConvention() && !Options.UseDataAnnotations))
            {
                if (keyFluentApiCalls != null)
                {
                    usings.AddRange(keyFluentApiCalls.GetRequiredUsings());
                }
#>
            entity.HasKey(<#= code.Lambda(key.Properties, "e") #>)<#= code.Fragment(keyFluentApiCalls, indent: 4) #>;
<#
                anyEntityTypeConfiguration = true;
            }
        }

        var entityTypeFluentApiCalls = entityType.GetFluentApiCalls(annotationCodeGenerator)
            ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations));
        if (entityTypeFluentApiCalls != null)
        {
            usings.AddRange(entityTypeFluentApiCalls.GetRequiredUsings());

            if (anyEntityTypeConfiguration)
            {
                WriteLine("");
            }
#>
            entity<#= code.Fragment(entityTypeFluentApiCalls, indent: 4) #>;
<#
            anyEntityTypeConfiguration = true;
        }

        foreach (var index in entityType.GetIndexes()
            .Where(i => !(Options.UseDataAnnotations && i.IsHandledByDataAnnotations(annotationCodeGenerator))))
        {
            if (anyEntityTypeConfiguration)
            {
                WriteLine("");
            }

            var indexFluentApiCalls = index.GetFluentApiCalls(annotationCodeGenerator);
            if (indexFluentApiCalls != null)
            {
                usings.AddRange(indexFluentApiCalls.GetRequiredUsings());
            }
#>
            entity.HasIndex(<#= code.Lambda(index.Properties, "e") #>, <#= code.Literal(index.GetDatabaseName()) #>)<#= code.Fragment(indexFluentApiCalls, indent: 4) #>;
<#
            anyEntityTypeConfiguration = true;
        }

        var firstProperty = true;
        foreach (var property in entityType.GetProperties())
        {
            var propertyFluentApiCalls = property.GetFluentApiCalls(annotationCodeGenerator)
                ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations)
                    && !(c.Method == "IsRequired" && Options.UseNullableReferenceTypes && !property.ClrType.IsValueType));
            if (propertyFluentApiCalls == null)
            {
                continue;
            }

            usings.AddRange(propertyFluentApiCalls.GetRequiredUsings());

            if (anyEntityTypeConfiguration && firstProperty)
            {
                WriteLine("");
            }
#>
            entity.Property(e => e.<#= property.Name #>)<#= code.Fragment(propertyFluentApiCalls, indent: 4) #>;
<#
            anyEntityTypeConfiguration = true;
            firstProperty = false;
        }

        foreach (var foreignKey in entityType.GetForeignKeys())
        {
            var foreignKeyFluentApiCalls = foreignKey.GetFluentApiCalls(annotationCodeGenerator)
                ?.FilterChain(c => !(Options.UseDataAnnotations && c.IsHandledByDataAnnotations));
            if (foreignKeyFluentApiCalls == null)
            {
                continue;
            }

            usings.AddRange(foreignKeyFluentApiCalls.GetRequiredUsings());

            if (anyEntityTypeConfiguration)
            {
                WriteLine("");
            }
#>
            entity.HasOne(d => d.<#= foreignKey.DependentToPrincipal.Name #>).<#= foreignKey.IsUnique ? "WithOne" : "WithMany" #>(<#= foreignKey.PrincipalToDependent != null ? $"p => p.{foreignKey.PrincipalToDependent.Name}" : "" #>)<#= code.Fragment(foreignKeyFluentApiCalls, indent: 4) #>;
<#
            anyEntityTypeConfiguration = true;
        }

        foreach (var skipNavigation in entityType.GetSkipNavigations().Where(n => n.IsLeftNavigation()))
        {
            if (anyEntityTypeConfiguration)
            {
                WriteLine("");
            }

            var left = skipNavigation.ForeignKey;
            var leftFluentApiCalls = left.GetFluentApiCalls(annotationCodeGenerator, useStrings: true);
            var right = skipNavigation.Inverse.ForeignKey;
            var rightFluentApiCalls = right.GetFluentApiCalls(annotationCodeGenerator, useStrings: true);
            var joinEntityType = skipNavigation.JoinEntityType;

            if (leftFluentApiCalls != null)
            {
                usings.AddRange(leftFluentApiCalls.GetRequiredUsings());
            }

            if (rightFluentApiCalls != null)
            {
                usings.AddRange(rightFluentApiCalls.GetRequiredUsings());
            }
#>
            entity.HasMany(d => d.<#= skipNavigation.Name #>).WithMany(p => p.<#= skipNavigation.Inverse.Name #>)
                .UsingEntity<Dictionary<string, object>>(
                    <#= code.Literal(joinEntityType.Name) #>,
                    r => r.HasOne<<#= right.PrincipalEntityType.Name #>>().WithMany()<#= code.Fragment(rightFluentApiCalls, indent: 6) #>,
                    l => l.HasOne<<#= left.PrincipalEntityType.Name #>>().WithMany()<#= code.Fragment(leftFluentApiCalls, indent: 6) #>,
                    j =>
                    {
<#
            var joinKey = joinEntityType.FindPrimaryKey();
            var joinKeyFluentApiCalls = joinKey.GetFluentApiCalls(annotationCodeGenerator);

            if (joinKeyFluentApiCalls != null)
            {
                usings.AddRange(joinKeyFluentApiCalls.GetRequiredUsings());
            }
#>
                        j.HasKey(<#= code.Arguments(joinKey.Properties.Select(e => e.Name)) #>)<#= code.Fragment(joinKeyFluentApiCalls, indent: 7) #>;
<#
            var joinEntityTypeFluentApiCalls = joinEntityType.GetFluentApiCalls(annotationCodeGenerator);
            if (joinEntityTypeFluentApiCalls != null)
            {
                usings.AddRange(joinEntityTypeFluentApiCalls.GetRequiredUsings());
#>
                        j<#= code.Fragment(joinEntityTypeFluentApiCalls, indent: 7) #>;
<#
            }

            foreach (var index in joinEntityType.GetIndexes())
            {
                var indexFluentApiCalls = index.GetFluentApiCalls(annotationCodeGenerator);
                if (indexFluentApiCalls != null)
                {
                    usings.AddRange(indexFluentApiCalls.GetRequiredUsings());
                }
#>
                        j.HasIndex(<#= code.Literal(index.Properties.Select(e => e.Name).ToArray()) #>, <#= code.Literal(index.GetDatabaseName()) #>)<#= code.Fragment(indexFluentApiCalls, indent: 7) #>;
<#
            }

            foreach (var property in joinEntityType.GetProperties())
            {
                var propertyFluentApiCalls = property.GetFluentApiCalls(annotationCodeGenerator);
                if (propertyFluentApiCalls == null)
                {
                    continue;
                }

                usings.AddRange(propertyFluentApiCalls.GetRequiredUsings());
#>
             j.IndexerProperty<<#= code.Reference(property.ClrType) #>>(<#= code.Literal(property.Name) #>)<#= code.Fragment(propertyFluentApiCalls, indent: 7) #>;
           
<#
            }
#>
                    });
<#
            anyEntityTypeConfiguration = true;
        }

#>
            //添加全局筛选器
            if (this.TenantInfo != null)
            {
                entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
            }
        });
<#
        // If any signicant code was generated, append it to the main environment
        if (anyEntityTypeConfiguration)
        {
            mainEnvironment.Append(GenerationEnvironment);
            anyConfiguration = true;
        }

        // Resume generating code into the main environment
        GenerationEnvironment = mainEnvironment;
    }

    foreach (var sequence in Model.GetSequences())
    {
        var needsType = sequence.Type != typeof(long);
        var needsSchema = !string.IsNullOrEmpty(sequence.Schema) && sequence.Schema != sequence.Model.GetDefaultSchema();
        var sequenceFluentApiCalls = sequence.GetFluentApiCalls(annotationCodeGenerator);
#>
        modelBuilder.HasSequence<#= needsType ? $"<{code.Reference(sequence.Type)}>" : "" #>(<#= code.Literal(sequence.Name) #><#= needsSchema ? $", {code.Literal(sequence.Schema)}" : "" #>)<#= code.Fragment(sequenceFluentApiCalls, indent: 3) #>;
<#
    }

    if (anyConfiguration)
    {
        WriteLine("");
    }
#>
        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
<#
    mainEnvironment = GenerationEnvironment;
    GenerationEnvironment = new StringBuilder();

    foreach (var ns in usings.Distinct().OrderBy(x => x, new NamespaceComparer()))
    {
#>
using <#= ns #>;
<#
    }

    WriteLine("");

    GenerationEnvironment.Append(mainEnvironment);
#>
