using OrderPROPrint.Forms;

namespace OrderPROPrint.Services;

public class PollingService
{
    private readonly PrintApiClient _apiClient;
    private readonly PrintService _printService;
    private readonly string _printerName;
    private readonly int _intervalSeconds;
    private readonly Action<string> _onStatusUpdate;
    private readonly Action<string> _onError;

    private System.Threading.Timer? _timer;
    private bool _isProcessing;
    private int _totalPrinted;
    private readonly object _lock = new();

    public bool IsRunning { get; private set; }

    public PollingService(
        PrintApiClient apiClient,
        PrintService printService,
        string printerName,
        int intervalSeconds,
        Action<string> onStatusUpdate,
        Action<string> onError)
    {
        _apiClient = apiClient;
        _printService = printService;
        _printerName = printerName;
        _intervalSeconds = Math.Max(intervalSeconds, 5);
        _onStatusUpdate = onStatusUpdate;
        _onError = onError;
    }

    public void Start()
    {
        if (IsRunning) return;

        IsRunning = true;
        _timer = new System.Threading.Timer(
            async _ => await PollAsync(),
            null,
            TimeSpan.Zero,
            TimeSpan.FromSeconds(_intervalSeconds)
        );

        _onStatusUpdate($"Aktywne (co {_intervalSeconds}s)");
    }

    public void Stop()
    {
        IsRunning = false;
        _timer?.Change(Timeout.Infinite, Timeout.Infinite);
        _timer?.Dispose();
        _timer = null;
    }

    private async Task PollAsync()
    {
        lock (_lock)
        {
            if (_isProcessing) return;
            _isProcessing = true;
        }

        try
        {
            var jobs = await _apiClient.GetPendingJobsAsync();
            LogForm.Log($"Polling: znaleziono {jobs.Count} zleceń");

            if (jobs.Count == 0)
            {
                _onStatusUpdate($"Brak zleceń (wydrukowano: {_totalPrinted})");
                return;
            }

            int printed = 0;
            int failed = 0;

            string lastError = "";
            foreach (var job in jobs)
            {
                try
                {
                    LogForm.Log($"Job {job.Id}: pobieranie etykiety...");
                    var labelBytes = await _apiClient.DownloadLabelAsync(job.Id);
                    LogForm.Log($"Job {job.Id}: pobrano {labelBytes.Length} bajtów");

                    if (labelBytes.Length == 0)
                    {
                        failed++;
                        lastError = $"Job {job.Id}: pusty plik etykiety";
                        LogForm.Log($"BŁĄD: {lastError}");
                        continue;
                    }

                    LogForm.Log($"Job {job.Id}: drukowanie na '{_printerName}'...");
                    bool success = _printService.PrintPdf(labelBytes, _printerName);

                    if (success)
                    {
                        await _apiClient.MarkCompleteAsync(job.Id);
                        printed++;
                        _totalPrinted++;
                        LogForm.Log($"Job {job.Id}: wydrukowano i oznaczono jako complete ✓");
                    }
                    else
                    {
                        failed++;
                        lastError = $"Job {job.Id}: druk nie powiódł się";
                        LogForm.Log($"BŁĄD: {lastError}");
                    }
                }
                catch (HttpRequestException ex)
                {
                    failed++;
                    lastError = $"Job {job.Id}: HTTP {ex.StatusCode} — {ex.Message}";
                    LogForm.Log($"BŁĄD: {lastError}");
                }
                catch (Exception ex)
                {
                    failed++;
                    lastError = $"Job {job.Id}: {ex.GetType().Name} — {ex.Message}";
                    LogForm.Log($"BŁĄD: {lastError}");
                }
            }

            if (failed > 0)
            {
                _onStatusUpdate($"Wydrukowano: {printed}, błędy: {failed} (łącznie: {_totalPrinted})");
            }
            else
            {
                _onStatusUpdate($"Wydrukowano {printed} etykiet (łącznie: {_totalPrinted})");
            }
        }
        catch (HttpRequestException ex)
        {
            _onError($"API niedostępne: {ex.Message}");
        }
        catch (TaskCanceledException)
        {
            _onError("Timeout połączenia z API");
        }
        catch (Exception ex)
        {
            _onError(ex.Message);
        }
        finally
        {
            lock (_lock)
            {
                _isProcessing = false;
            }
        }
    }
}
