<Project>

    <!--
    为 GFramework 运行时包生成可选的模块级 transitive global usings。
    该逻辑只在明确启用的可打包项目中生效，并在构建/打包期间自动扫描源码命名空间。
    -->
    <UsingTask TaskName="GenerateGFrameworkTransitiveGlobalUsingsProps"
               TaskFactory="RoslynCodeTaskFactory"
               AssemblyFile="$(MSBuildToolsPath)/Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <SourceFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true"/>
            <ExcludedNamespaces ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
            <ExcludedNamespacePrefixes ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
            <OutputFile ParameterType="System.String" Required="true"/>
            <NamespaceItemName ParameterType="System.String" Required="true"/>
        </ParameterGroup>
        <Task>
            <Code Type="Fragment"
                  Language="cs"><![CDATA[
                var discoveredNamespaces = new global::System.Collections.Generic.SortedSet<string>(global::System.StringComparer.Ordinal);
                var exactExclusions = new global::System.Collections.Generic.HashSet<string>(global::System.StringComparer.Ordinal);
                var prefixExclusions = new global::System.Collections.Generic.List<string>();
                var namespacePattern = new global::System.Text.RegularExpressions.Regex(
                    @"^\s*namespace\s+([A-Za-z_][A-Za-z0-9_.]*)\s*(?:;|\{)",
                    global::System.Text.RegularExpressions.RegexOptions.Compiled);

                if (ExcludedNamespaces != null)
                {
                    foreach (var excludedNamespace in ExcludedNamespaces)
                    {
                        if (!string.IsNullOrWhiteSpace(excludedNamespace.ItemSpec))
                        {
                            exactExclusions.Add(excludedNamespace.ItemSpec.Trim());
                        }
                    }
                }

                if (ExcludedNamespacePrefixes != null)
                {
                    foreach (var excludedPrefix in ExcludedNamespacePrefixes)
                    {
                        if (!string.IsNullOrWhiteSpace(excludedPrefix.ItemSpec))
                        {
                            prefixExclusions.Add(excludedPrefix.ItemSpec.Trim());
                        }
                    }
                }

                foreach (var sourceFile in SourceFiles)
                {
                    var path = sourceFile.ItemSpec;
                    if (!global::System.IO.File.Exists(path))
                    {
                        continue;
                    }

                    foreach (var line in global::System.IO.File.ReadLines(path))
                    {
                        var match = namespacePattern.Match(line);
                        if (!match.Success)
                        {
                            continue;
                        }

                        var namespaceName = match.Groups[1].Value;
                        if (!namespaceName.StartsWith("GFramework.", global::System.StringComparison.Ordinal))
                        {
                            continue;
                        }

                        if (exactExclusions.Contains(namespaceName))
                        {
                            continue;
                        }

                        var excludedByPrefix = false;
                        foreach (var prefix in prefixExclusions)
                        {
                            if (namespaceName.StartsWith(prefix, global::System.StringComparison.Ordinal))
                            {
                                excludedByPrefix = true;
                                break;
                            }
                        }

                        if (!excludedByPrefix)
                        {
                            discoveredNamespaces.Add(namespaceName);
                        }
                    }
                }

                static string Escape(string value)
                {
                    return global::System.Security.SecurityElement.Escape(value) ?? value;
                }

                var directory = global::System.IO.Path.GetDirectoryName(OutputFile);
                if (!string.IsNullOrEmpty(directory))
                {
                    global::System.IO.Directory.CreateDirectory(directory);
                }

                var builder = new global::System.Text.StringBuilder();
                var msbuildPropertyOpen = new string(new[] { '$', '(' });
                var msbuildItemOpen = new string(new[] { '@', '(' });
                builder.AppendLine("<Project>");
                builder.AppendLine("  <!-- This file is generated by GFramework's MSBuild transitive global usings pipeline. -->");
                builder.AppendLine("  <!-- EnableGFrameworkGlobalUsings=true enables the transitive global usings from this package. -->");
                builder.AppendLine("  <!-- Add <GFrameworkExcludedUsing Include=\"Namespace\" /> to opt out of specific namespaces. -->");
                builder.Append("  <ItemGroup Condition=\"'");
                builder.Append(msbuildPropertyOpen);
                builder.AppendLine("EnableGFrameworkGlobalUsings)' == 'true'\">");

                foreach (var namespaceName in discoveredNamespaces)
                {
                    builder.Append("    <");
                    builder.Append(NamespaceItemName);
                    builder.Append(" Include=\"");
                    builder.Append(Escape(namespaceName));
                    builder.AppendLine("\" />");
                }

                builder.Append("    <");
                builder.Append(NamespaceItemName);
                builder.Append(" Remove=\"");
                builder.Append(msbuildItemOpen);
                builder.AppendLine("GFrameworkExcludedUsing)\" />");
                builder.Append("    <Using Include=\"");
                builder.Append(msbuildItemOpen);
                builder.Append(NamespaceItemName);
                builder.AppendLine(")\" />");
                builder.AppendLine("  </ItemGroup>");
                builder.AppendLine("</Project>");

                global::System.IO.File.WriteAllText(OutputFile, builder.ToString(), new global::System.Text.UTF8Encoding(false));
                Log.LogMessage(global::Microsoft.Build.Framework.MessageImportance.Low,
                    $"Generated {discoveredNamespaces.Count} transitive global usings for {OutputFile}.");
            ]]></Code>
        </Task>
    </UsingTask>

    <PropertyGroup>
        <_GFrameworkTransitiveGlobalUsingsEnabled Condition="'$(EnableGFrameworkPackageTransitiveGlobalUsings)' == 'true' and '$(IsPackable)' != 'false'">true</_GFrameworkTransitiveGlobalUsingsEnabled>
        <_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(TargetFrameworks)' != ''">$([System.String]::Copy('$(TargetFrameworks)').Split(';')[0])</_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework>
        <_GFrameworkTransitiveGlobalUsingsGenerationBuild Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and ('$(TargetFrameworks)' == '' or '$(TargetFramework)' == '$(_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework)')">true</_GFrameworkTransitiveGlobalUsingsGenerationBuild>
        <_GFrameworkTransitiveGlobalUsingsPackageId Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(PackageId)' != ''">$(PackageId)</_GFrameworkTransitiveGlobalUsingsPackageId>
        <_GFrameworkTransitiveGlobalUsingsPackageId Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(_GFrameworkTransitiveGlobalUsingsPackageId)' == ''">$(AssemblyName)</_GFrameworkTransitiveGlobalUsingsPackageId>
        <_GFrameworkTransitiveGlobalUsingsOutputFile Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">$(BaseIntermediateOutputPath)gframework/$(_GFrameworkTransitiveGlobalUsingsPackageId).props</_GFrameworkTransitiveGlobalUsingsOutputFile>
        <_GFrameworkTransitiveGlobalUsingsItemName Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">_$([System.Text.RegularExpressions.Regex]::Replace('$(MSBuildProjectName)', '[^A-Za-z0-9_]', '_'))_TransitiveUsing</_GFrameworkTransitiveGlobalUsingsItemName>
    </PropertyGroup>

    <ItemGroup Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">
        <None Include="$(_GFrameworkTransitiveGlobalUsingsOutputFile)"
              Pack="true"
              PackagePath="buildTransitive"
              Visible="false"/>
    </ItemGroup>

    <Target Name="GenerateGFrameworkModuleTransitiveGlobalUsings"
            Condition="'$(_GFrameworkTransitiveGlobalUsingsGenerationBuild)' == 'true'"
            BeforeTargets="CoreCompile;GenerateNuspec">
        <GenerateGFrameworkTransitiveGlobalUsingsProps
                SourceFiles="@(Compile->'%(FullPath)')"
                ExcludedNamespaces="@(GFrameworkTransitiveUsingExclude)"
                ExcludedNamespacePrefixes="@(GFrameworkTransitiveUsingExcludePrefix)"
                OutputFile="$(_GFrameworkTransitiveGlobalUsingsOutputFile)"
                NamespaceItemName="$(_GFrameworkTransitiveGlobalUsingsItemName)"/>
    </Target>

</Project>
