using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Tornado3_2026Election.Domain;

namespace Tornado3_2026Election.Services;

public sealed class KarismaThumbnailGeneratorService
{
    private const int DefaultKarismaPort = 30001;
    private const int ThumbnailFrame = -1;
    private readonly LogService _logService;

    public KarismaThumbnailGeneratorService(LogService logService)
    {
        _logService = logService;
    }

    public static bool IsGenerationAvailable()
    {
        return CutThumbnailAssetCatalog.TryGetProjectAssetRoot() is not null;
    }

    public async Task<ThumbnailGenerationResult> GenerateAsync(
        IReadOnlyList<FormatTemplateDefinition> templates,
        string configuredT3CutPath,
        VideoWallLayoutPreset videoWallLayoutPreset,
        CancellationToken cancellationToken)
    {
        var t3CutPath = TornadoPathResolver.GetDefaultT3CutPath();

        if (string.IsNullOrWhiteSpace(t3CutPath) || !Directory.Exists(t3CutPath))
        {
            throw new DirectoryNotFoundException("유효한 T3_Cut 경로를 찾지 못했습니다.");
        }

        var (host, port) = ResolveConnectionSettings();
        using var manager = new TornadoManager(host, port, _logService);
        return await GenerateAsync(
            manager,
            templates,
            t3CutPath,
            videoWallLayoutPreset,
            cancellationToken).ConfigureAwait(false);
    }

    public async Task<ThumbnailGenerationResult> GenerateAsync(
        TornadoManager manager,
        IReadOnlyList<FormatTemplateDefinition> templates,
        string t3CutPath,
        VideoWallLayoutPreset videoWallLayoutPreset,
        CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(t3CutPath) || !Directory.Exists(t3CutPath))
        {
            throw new DirectoryNotFoundException("유효한 T3_Cut 경로를 찾지 못했습니다.");
        }

        var projectAssetRoot = CutThumbnailAssetCatalog.TryGetProjectAssetRoot();
        if (string.IsNullOrWhiteSpace(projectAssetRoot))
        {
            throw new InvalidOperationException("프로젝트 내부 Assets\\Thumbnail 경로를 찾지 못했습니다.");
        }

        Directory.CreateDirectory(projectAssetRoot);

        var generatedCount = 0;
        var failedCount = 0;

        await manager.EnsureConnectedAsync(cancellationToken).ConfigureAwait(false);

        foreach (var template in templates.OrderBy(template => template.Id, StringComparer.Ordinal))
        {
            cancellationToken.ThrowIfCancellationRequested();

            var targetPath = CutThumbnailAssetCatalog.TryGetProjectAssetPath(template);
            if (string.IsNullOrWhiteSpace(targetPath))
            {
                failedCount++;
                _logService.Warning($"[Thumbnail] 프로젝트 썸네일 경로를 만들지 못했습니다: {template.Id}");
                continue;
            }

            string? sceneAlias = null;

            try
            {
                var resolvedScene = KarismaSceneResolver.ResolveScene(template, t3CutPath, useLoop: false);
                sceneAlias = $"{resolvedScene.Alias}__thumbnail";

                var targetDirectory = Path.GetDirectoryName(targetPath);
                if (!string.IsNullOrWhiteSpace(targetDirectory))
                {
                    Directory.CreateDirectory(targetDirectory);
                }

                var thumbnailSize = ThumbnailLayoutResolver.ResolveGenerationSize(template, videoWallLayoutPreset);
                await manager.LoadSceneAsync(resolvedScene.Path, resolvedScene.Alias, cancellationToken).ConfigureAwait(false);
                await manager.SaveSceneImageAsync(
                    resolvedScene.Alias,
                    targetPath,
                    thumbnailSize.Width,
                    thumbnailSize.Height,
                    ThumbnailFrame,
                    cancellationToken).ConfigureAwait(false);

                generatedCount++;
                _logService.Info($"[Thumbnail] 저장 완료: {template.Id} -> {targetPath}");
            }
            catch (Exception ex)
            {
                failedCount++;
                _logService.Warning($"[Thumbnail] 저장 실패: {template.Id} / {ex.Message}");
            }
            finally
            {
                if (!string.IsNullOrWhiteSpace(sceneAlias))
                {
                    try
                    {
                        await manager.UnloadSceneAsync(sceneAlias, cancellationToken).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        _logService.Warning($"[Thumbnail] 언로드 실패: {sceneAlias} / {ex.Message}");
                    }
                }
            }
        }

        return new ThumbnailGenerationResult(generatedCount, failedCount);
    }

    private static (string Host, int Port) ResolveConnectionSettings()
    {
        var host = Environment.GetEnvironmentVariable("TORNADO_KARISMA_HOST");
        if (string.IsNullOrWhiteSpace(host))
        {
            host = "127.0.0.1";
        }

        if (!int.TryParse(Environment.GetEnvironmentVariable("TORNADO_KARISMA_PORT"), out var port) || port <= 0)
        {
            port = DefaultKarismaPort;
        }

        return (host, port);
    }
}

public readonly record struct ThumbnailGenerationResult(int GeneratedCount, int FailedCount)
{
    public int TotalCount => GeneratedCount + FailedCount;
}
