using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Tornado3_2026Election.Domain;

namespace Tornado3_2026Election.Services;

public static class CutThumbnailAssetCatalog
{
    private const string ThumbnailAssetRoot = @"Assets\Thumbnail";
    private const string FallbackAssetPath = @"Assets\AppIcon.png";

    public static string GetRelativeAssetPath(FormatTemplateDefinition template)
    {
        return GetRelativeAssetPath(template.Id);
    }

    public static string GetRelativeAssetPath(string templateId)
    {
        var normalizedId = templateId
            .Replace('\\', Path.DirectorySeparatorChar)
            .Replace('/', Path.DirectorySeparatorChar);

        return Path.Combine(ThumbnailAssetRoot, normalizedId + ".png");
    }

    public static string GetBundledAssetPath(FormatTemplateDefinition template)
    {
        return GetBundledAssetPath(template.Id);
    }

    public static string GetBundledAssetPath(string templateId)
    {
        return Path.Combine(AppContext.BaseDirectory, GetRelativeAssetPath(templateId));
    }

    public static string? TryGetProjectAssetRoot()
    {
        var projectRoot = TryGetProjectRoot();
        return projectRoot is null
            ? null
            : Path.Combine(projectRoot, "Assets", "Thumbnail");
    }

    public static string? TryGetProjectAssetPath(FormatTemplateDefinition template)
    {
        return TryGetProjectAssetPath(template.Id);
    }

    public static string? TryGetProjectAssetPath(string templateId)
    {
        var assetRoot = TryGetProjectAssetRoot();
        if (assetRoot is null)
        {
            return null;
        }

        var relativeWithinAssets = templateId
            .Replace('\\', Path.DirectorySeparatorChar)
            .Replace('/', Path.DirectorySeparatorChar) + ".png";

        return Path.Combine(assetRoot, relativeWithinAssets);
    }

    public static bool HasThumbnail(FormatTemplateDefinition template)
    {
        return HasThumbnail(template.Id);
    }

    public static bool HasThumbnail(string templateId)
    {
        foreach (var candidateTemplateId in EnumerateThumbnailTemplateIds(templateId))
        {
            if (HasThumbnailPath(candidateTemplateId))
            {
                return true;
            }
        }

        return false;
    }

    private static bool HasThumbnailPath(string templateId)
    {
        var projectPath = TryGetProjectAssetPath(templateId);
        if (!string.IsNullOrWhiteSpace(projectPath) && File.Exists(projectPath))
        {
            return true;
        }

        return File.Exists(GetBundledAssetPath(templateId));
    }

    public static ImageSource? CreateImageSource(FormatTemplateDefinition template)
    {
        return CreateImageSource(template.Id);
    }

    public static ImageSource? CreateImageSource(string templateId)
    {
        var preferredPath = ResolvePreferredDisplayPath(templateId);
        return File.Exists(preferredPath)
            ? new BitmapImage(new Uri(preferredPath, UriKind.Absolute))
            : null;
    }

    public static string ResolvePreferredDisplayPath(FormatTemplateDefinition template)
    {
        return ResolvePreferredDisplayPath(template.Id);
    }

    public static string ResolvePreferredDisplayPath(string templateId)
    {
        foreach (var candidateTemplateId in EnumerateThumbnailTemplateIds(templateId))
        {
            var projectPath = TryGetProjectAssetPath(candidateTemplateId);
            if (!string.IsNullOrWhiteSpace(projectPath) && File.Exists(projectPath))
            {
                return projectPath;
            }

            var bundledPath = GetBundledAssetPath(candidateTemplateId);
            if (File.Exists(bundledPath))
            {
                return bundledPath;
            }
        }

        return Path.Combine(AppContext.BaseDirectory, FallbackAssetPath);
    }

    private static IEnumerable<string> EnumerateThumbnailTemplateIds(string templateId)
    {
        var preferredTemplateId = ResolvePreferredThumbnailTemplateId(templateId);
        if (!string.Equals(preferredTemplateId, templateId, StringComparison.Ordinal))
        {
            yield return preferredTemplateId;
            yield return templateId;
            yield break;
        }

        yield return templateId;

        var fallbackTemplateId = ResolveThumbnailTemplateId(templateId);
        if (!string.Equals(templateId, fallbackTemplateId, StringComparison.Ordinal))
        {
            yield return fallbackTemplateId;
        }
    }

    private static string ResolvePreferredThumbnailTemplateId(string templateId)
    {
        if (string.IsNullOrWhiteSpace(templateId))
        {
            return templateId;
        }

        var normalizedId = templateId.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
        var folder = Path.GetDirectoryName(normalizedId);
        var fileName = Path.GetFileName(normalizedId);

        if (folder is not null &&
            string.Equals(folder, "Elect2026_Normal_민방", StringComparison.Ordinal) &&
            string.Equals(fileName, "투표율", StringComparison.Ordinal))
        {
            return Path.Combine(folder, "투표율_사진");
        }

        return templateId;
    }

    private static string ResolveThumbnailTemplateId(string templateId)
    {
        if (string.IsNullOrWhiteSpace(templateId))
        {
            return templateId;
        }

        var normalizedId = templateId.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
        var folder = Path.GetDirectoryName(normalizedId);
        var fileName = Path.GetFileName(normalizedId);
        var canonicalName = fileName switch
        {
            "사전투표율_시도" or "사전투표율_시군구" => "사전투표율",
            "투표율_시도" or "투표율_시군구" => "투표율",
            _ => fileName
        };

        return string.Equals(fileName, canonicalName, StringComparison.Ordinal)
            ? templateId
            : string.IsNullOrWhiteSpace(folder)
                ? canonicalName
                : Path.Combine(folder, canonicalName);
    }

    private static string? TryGetProjectRoot()
    {
        var current = new DirectoryInfo(AppContext.BaseDirectory);
        while (current is not null)
        {
            if (File.Exists(Path.Combine(current.FullName, "Tornado3_2026Election.csproj")))
            {
                return current.FullName;
            }

            current = current.Parent;
        }

        return null;
    }
}
