using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;

namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Output.Visualization;

/// <summary>按准确族名解析报告所需字体，并提供混合中英文文本的共同基线度量。</summary>
public sealed class SmoothingFontResolver
{
    public bool TryResolve(
        string chineseFamilyName,
        string latinFamilyName,
        out SmoothingFontResolution resolution,
        out string reason)
    {
        resolution = null;
        reason = string.Empty;
        if (string.IsNullOrWhiteSpace(chineseFamilyName) || string.IsNullOrWhiteSpace(latinFamilyName))
        {
            reason = "中文和拉丁字体族名均不能为空。";
            return false;
        }

        var collection = new InstalledFontCollection();
        FontFamily chinese = FindExact(collection.Families, chineseFamilyName);
        FontFamily latin = FindExact(collection.Families, latinFamilyName);
        if (chinese == null || latin == null)
        {
            collection.Dispose();
            reason = "未安装报告所需的精确字体族：" + (chinese == null ? chineseFamilyName : latinFamilyName) + "。";
            return false;
        }

        resolution = new SmoothingFontResolution(collection, chinese, latin, chineseFamilyName, latinFamilyName);
        return true;
    }

    public RectangleF MeasureMixedText(SmoothingFontResolution resolution, string text, float points)
    {
        if (resolution == null) throw new ArgumentNullException(nameof(resolution));
        if (string.IsNullOrEmpty(text) || points <= 0f) return RectangleF.Empty;
        using (var bitmap = new Bitmap(1, 1))
        using (Graphics graphics = Graphics.FromImage(bitmap))
        using (var format = (StringFormat)StringFormat.GenericTypographic.Clone())
        {
            format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
            float width = 0f, height = 0f;
            foreach (TextRun run in SplitRuns(text))
            {
                using (Font font = resolution.CreateFont(run.IsChinese ? resolution.ChineseFamily : resolution.LatinFamily, points))
                {
                    SizeF size = graphics.MeasureString(run.Text, font, PointF.Empty, format);
                    width += size.Width;
                    height = Math.Max(height, size.Height);
                }
            }
            return new RectangleF(0f, 0f, width, height);
        }
    }

    internal static IReadOnlyList<TextRun> SplitRuns(string text)
    {
        var runs = new List<TextRun>();
        if (string.IsNullOrEmpty(text)) return runs;
        int start = 0;
        bool isChinese = IsChinese(text[0]);
        for (int index = 1; index < text.Length; index++)
        {
            bool currentIsChinese = IsChinese(text[index]);
            if (currentIsChinese == isChinese) continue;
            runs.Add(new TextRun(text.Substring(start, index - start), isChinese));
            start = index;
            isChinese = currentIsChinese;
        }
        runs.Add(new TextRun(text.Substring(start), isChinese));
        return runs;
    }

    private static FontFamily FindExact(IReadOnlyList<FontFamily> families, string name)
    {
        for (int index = 0; index < families.Count; index++)
        {
            FontFamily family = families[index];
            if (string.Equals(family.Name, name, StringComparison.Ordinal) ||
                string.Equals(family.GetName(1033), name, StringComparison.Ordinal)) return family;
        }
        return null;
    }

    private static bool IsChinese(char value)
    {
        return (value >= 0x3400 && value <= 0x4dbf) || (value >= 0x4e00 && value <= 0x9fff) ||
            (value >= 0xf900 && value <= 0xfaff) || value == 0x3002 || value == 0xff0c || value == 0xff1a;
    }

    internal sealed class TextRun
    {
        public TextRun(string text, bool isChinese) { Text = text; IsChinese = isChinese; }
        public string Text { get; }
        public bool IsChinese { get; }
    }
}

/// <summary>一次报告导出所使用的精确字体族；释放时同时释放字体集合。</summary>
public sealed class SmoothingFontResolution : IDisposable
{
    private readonly InstalledFontCollection _collection;
    private readonly string _chineseFamilyName;
    private readonly string _latinFamilyName;

    internal SmoothingFontResolution(
        InstalledFontCollection collection,
        FontFamily chineseFamily,
        FontFamily latinFamily,
        string chineseFamilyName,
        string latinFamilyName)
    {
        _collection = collection ?? throw new ArgumentNullException(nameof(collection));
        ChineseFamily = chineseFamily ?? throw new ArgumentNullException(nameof(chineseFamily));
        LatinFamily = latinFamily ?? throw new ArgumentNullException(nameof(latinFamily));
        _chineseFamilyName = chineseFamilyName ?? throw new ArgumentNullException(nameof(chineseFamilyName));
        _latinFamilyName = latinFamilyName ?? throw new ArgumentNullException(nameof(latinFamilyName));
    }

    public string ChineseFamilyName => _chineseFamilyName;
    public string LatinFamilyName => _latinFamilyName;
    internal FontFamily ChineseFamily { get; }
    internal FontFamily LatinFamily { get; }

    internal Font CreateFont(FontFamily family, float points)
    {
        return new Font(family, points, FontStyle.Regular, GraphicsUnit.Point);
    }

    public void Dispose()
    {
        _collection.Dispose();
    }
}
