using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;

namespace PCL.Core.App.Configuration;

public delegate void ConfigMigrationHandler(string from, string to);

/// <summary>
/// 配置文件迁移模型与工具。
/// </summary>
public class ConfigMigration
{
    /// <summary>
    /// 来源路径。
    /// </summary>
    public required string From { get; init; }

    /// <summary>
    /// 目标路径。
    /// </summary>
    public required string To { get; init; }

    /// <summary>
    /// 优先级 (或称"权重")，数字越大越容易被使用。
    /// </summary>
    public int Priority { get; init; } = 0;

    /// <summary>
    /// 迁移实现。
    /// </summary>
    public required ConfigMigrationHandler OnMigration { get; init; }

    /// <summary>
    /// 执行配置文件迁移。
    /// </summary>
    /// <param name="target">最终目标路径</param>
    /// <param name="migrations">可用的迁移过程</param>
    /// <returns>若找到最简方案并迁移成功，则为 <c>true</c>，否则为 <c>false</c></returns>
    public static bool Migrate(string target, IEnumerable<ConfigMigration> migrations)
    {
        migrations = migrations as ConfigMigration[] ?? migrations.ToArray();
        IEnumerable<ConfigMigration>? solution = null;
        var found = (
            from migration in migrations.Reverse()
            let path = migration.From
            where File.Exists(path) && _TryFindShortestPath(path, target, migrations, out solution)
            select path
        ).Any();
        if (!found) return false;
        foreach (var migration in solution!) migration.OnMigration(migration.From, migration.To);
        return true;
    }

    // 寻找最短路径
    // Partly generated by gpt-5 (20250904)
    // ReSharper disable InvertIf, ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
    private static bool _TryFindShortestPath(string start, string end,
        IEnumerable<ConfigMigration> paths, [NotNullWhen(true)] out IEnumerable<ConfigMigration>? result)
    {
        // 起点即终点：最短过程为 0 条边
        if (start == end)
        {
            result = [];
            return true;
        }

        // 构建邻接表（有向图）
        var adj = new Dictionary<string, List<ConfigMigration>>(StringComparer.Ordinal);
        foreach (var p in paths)
        {
            if (!adj.TryGetValue(p.From, out var list))
            {
                list = [];
                adj[p.From] = list;
            }
            list.Add(p);
        }

        // 第一阶段：BFS 计算从 start 到各点的最短边数 dist
        var dist = new Dictionary<string, int>(StringComparer.Ordinal);
        var queue = new Queue<string>();
        dist[start] = 0;
        queue.Enqueue(start);

        while (queue.Count > 0)
        {
            var u = queue.Dequeue();
            if (!adj.TryGetValue(u, out var outgoing))
                continue;
    
            var du = dist[u];
            foreach (var e in outgoing)
            {
                var v = e.To;
                if (!dist.ContainsKey(v))
                {
                    dist[v] = du + 1;
                    queue.Enqueue(v);
                }
            }
        }

        // 不可达
        if (!dist.ContainsKey(end))
        {
            result = null;
            return false;
        }

        // 将节点按深度分层，便于第二阶段的 DP
        var nodesByDepth = new Dictionary<int, List<string>>();
        foreach (var kv in dist)
        {
            if (!nodesByDepth.TryGetValue(kv.Value, out var list))
            {
                list = [];
                nodesByDepth[kv.Value] = list;
            }
            list.Add(kv.Key);
        }

        // 第二阶段：在所有最短路径子图上，选择累计 Priority 之和最大的路径
        var bestPriority = new Dictionary<string, long>(StringComparer.Ordinal); // 累计优先级和
        var prevNode = new Dictionary<string, string>(StringComparer.Ordinal);    // 重建路径
        var prevEdge = new Dictionary<string, ConfigMigration>(StringComparer.Ordinal);

        bestPriority[start] = 0;
        var maxDepth = dist[end];

        for (var d = 0; d < maxDepth; d++)
        {
            if (!nodesByDepth.TryGetValue(d, out var layer))
                continue;

            foreach (var u in layer)
            {
                if (!bestPriority.ContainsKey(u)) continue;

                if (!adj.TryGetValue(u, out var outgoing)) continue;

                foreach (var e in outgoing)
                {
                    if (!dist.TryGetValue(e.To, out var dv) || dv != d + 1)
                        continue; // 只考虑保持最短性的边

                    var candidate = bestPriority[u] + e.Priority;
                    if (!bestPriority.TryGetValue(e.To, out var cur) || candidate > cur)
                    {
                        bestPriority[e.To] = candidate;
                        prevNode[e.To] = u;
                        prevEdge[e.To] = e;
                    }
                }
            }
        }

        // 重建从 start 到 end 的路径（边序列）
        if (!prevEdge.ContainsKey(end)) { // 理论上不应发生
            result = null;
            return false;
        }
        var path = new List<ConfigMigration>();
        var curr = end;
        while (curr != start)
        {
            var edge = prevEdge[curr];
            path.Add(edge);
            curr = prevNode[curr];
        }
        path.Reverse();
        result = path;
        return true;
    }
    // ReSharper restore InvertIf, ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
}
