using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Tornado3_2026Election.Domain;

namespace Tornado3_2026Election.Services;

public sealed class MockTornado3Adapter : ITornado3Adapter
{
    private readonly LogService _logService;
    private TornadoConnectionState _state = TornadoConnectionState.Idle;

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

    public string BackendName => "Mock Adapter";

    public bool IsLiveCg => false;

    public bool IsConnected => false;

    public string ConnectionTarget => "실CG 미연동";

    public TornadoConnectionState State
    {
        get => _state;
        private set
        {
            if (_state == value)
            {
                return;
            }

            _state = value;
            StateChanged?.Invoke(this, value);
        }
    }

    public event EventHandler<TornadoConnectionState>? StateChanged;

    public event EventHandler? ConnectionChanged;

    public async Task EnsureConnectedAsync(CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            await Task.Delay(120, cancellationToken).ConfigureAwait(false);
            State = TornadoConnectionState.Ready;
            _logService.Info("Tornado3 mock adapter connected.");
        }, cancellationToken).ConfigureAwait(false);
    }

    public async Task ApplyCutAsync(
        BroadcastChannel channel,
        FormatTemplateDefinition template,
        FormatCutDefinition cut,
        ElectionDataSnapshot snapshot,
        BroadcastStationProfile station,
        string imageRootPath,
        CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            State = TornadoConnectionState.Sending;
            await Task.Delay(100, cancellationToken).ConfigureAwait(false);
            var summary = snapshot.BroadcastPhase == BroadcastPhase.PreElection
                ? $"turnout={snapshot.TurnoutRate:0.0}% voters={snapshot.TurnoutVotes:N0}"
                : $"leader={snapshot.Candidates.OrderByDescending(candidate => candidate.VoteCount).FirstOrDefault()?.Name ?? "없음"} counted={snapshot.CountedVotes:N0}";
            _logService.Info($"[{channel}] Apply {template.Name}/{cut.Name} station={station.Name} {summary} imageRoot={imageRootPath}");
            State = TornadoConnectionState.Ready;
        }, cancellationToken).ConfigureAwait(false);
    }

    public Task<bool> TryCapturePendingCutPreviewAsync(
        BroadcastChannel channel,
        string fileName,
        int width,
        int height,
        int frame,
        CancellationToken cancellationToken)
    {
        return Task.FromResult(false);
    }

    public Task<bool> TryCaptureCutPreviewAsync(
        BroadcastChannel channel,
        FormatTemplateDefinition template,
        FormatCutDefinition cut,
        ElectionDataSnapshot snapshot,
        BroadcastStationProfile station,
        string imageRootPath,
        string fileName,
        int width,
        int height,
        int frame,
        CancellationToken cancellationToken)
    {
        return Task.FromResult(false);
    }

    public async Task PrepareAsync(BroadcastChannel channel, CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            State = TornadoConnectionState.Ready;
            await Task.Delay(60, cancellationToken).ConfigureAwait(false);
            _logService.Info($"[{channel}] Prepare");
        }, cancellationToken).ConfigureAwait(false);
    }

    public async Task ShowPreparedFirstFrameAsync(BroadcastChannel channel, CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            State = TornadoConnectionState.Ready;
            await Task.Delay(40, cancellationToken).ConfigureAwait(false);
            _logService.Info($"[{channel}] Show prepared first frame on PGM");
        }, cancellationToken).ConfigureAwait(false);
    }

    public async Task TakeAsync(BroadcastChannel channel, CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            State = TornadoConnectionState.OnAir;
            await Task.Delay(60, cancellationToken).ConfigureAwait(false);
            _logService.Info($"[{channel}] Take");
        }, cancellationToken).ConfigureAwait(false);
    }

    public async Task ClearOutputAsync(BroadcastChannel channel, CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            State = TornadoConnectionState.Idle;
            await Task.Delay(30, cancellationToken).ConfigureAwait(false);
            _logService.Info($"[{channel}] Clear output layer");
        }, cancellationToken).ConfigureAwait(false);
    }

    public async Task OutAsync(BroadcastChannel channel, CancellationToken cancellationToken)
    {
        await ExecuteWithTimeoutAsync(async () =>
        {
            State = TornadoConnectionState.Idle;
            await Task.Delay(60, cancellationToken).ConfigureAwait(false);
            _logService.Info($"[{channel}] Layer Out");
        }, cancellationToken).ConfigureAwait(false);
    }

    private static async Task ExecuteWithTimeoutAsync(Func<Task> action, CancellationToken cancellationToken)
    {
        using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        timeoutCts.CancelAfter(TimeSpan.FromSeconds(5));
        await action().WaitAsync(timeoutCts.Token).ConfigureAwait(false);
    }
}
