using Emgu.CV;
using FaceRecognitionApp.Models;

namespace FaceRecognitionApp.Services;

public class CameraService : IDisposable
{
    private VideoCapture? _capture;
    private readonly FaceRecognitionService _recognition;
    private readonly Action<DetectedFace> _onDetected;
    private CancellationTokenSource? _cts;
    private Task? _task;
    private DateTime _lastTime = DateTime.MinValue;
    private bool _isDisposed = false;

    public CameraService(string url, FaceRecognitionService recognition, Action<DetectedFace> onDetected)
    {
        _recognition = recognition;
        _onDetected = onDetected;

        Console.WriteLine($"Initializing camera with URL: {url}");
        _capture = new VideoCapture(url);

        // Даем камере время на инициализацию потока
        Thread.Sleep(1000);

        if (!_capture.IsOpened)
            throw new Exception("Camera failed to open. Check URL and network connection.");

        Console.WriteLine("Camera hardware initialized.");
    }

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

        _cts = new CancellationTokenSource();
        _task = Task.Run(() => Loop(_cts.Token));
        Console.WriteLine("Camera processing loop started.");
    }

    private async Task Loop(CancellationToken token)
    {
        Console.WriteLine("🎥 Frame processing loop active...");

        while (!token.IsCancellationRequested)
        {
            try
            {
                using var frame = new Mat();

                // Читаем кадр с таймаутом
                if (_capture!.Read(frame))
                {
                    if (!frame.IsEmpty && frame.Width > 0 && frame.Height > 0)
                    {
                        var face = _recognition.ProcessFrame(frame);

                        if (face != null)
                        {
                            // Лимит частоты отправок (не чаще раза в 2 секунды)
                            if ((DateTime.Now - _lastTime).TotalMilliseconds > 2000)
                            {
                                _lastTime = DateTime.Now;
                                _onDetected(face);

                                string status = face.IsRecognized
                                    ? $"✅ Recognized: {face.MatchedEmployee?.Name}"
                                    : "❌ Unknown face";

                                Console.WriteLine($"{DateTime.Now:HH:mm:ss} - {status}");
                            }
                        }
                    }
                }
                else
                {
                    // Если Read вернул false, возможно потеря связи
                    Console.WriteLine("⚠️ Failed to read frame, retrying...");
                    await Task.Delay(500, token);
                }

                // Небольшая задержка, чтобы не грузить процессор на 100%
                await Task.Delay(50, token);
            }
            catch (OperationCanceledException)
            {
                // Это нормальная ситуация при остановке
                break;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"⚠️ Error in camera loop: {ex.Message}");
                await Task.Delay(1000, token);
            }
        }

        Console.WriteLine("🛑 Camera loop finished.");
    }

    public void Stop()
    {
        if (_cts == null) return;

        Console.WriteLine("Stopping camera service...");
        _cts.Cancel();

        try
        {
            // Ждем завершения задачи, но не бесконечно
            if (_task != null)
            {
                _task.Wait(TimeSpan.FromSeconds(5));
            }
        }
        catch (AggregateException ex)
        {
            // Игнорируем ошибки отмены задачи
            foreach (var inner in ex.InnerExceptions)
            {
                if (!(inner is TaskCanceledException || inner is OperationCanceledException))
                {
                    Console.WriteLine($"Unexpected error during stop: {inner.Message}");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error stopping task: {ex.Message}");
        }
    }

    public void Dispose()
    {
        if (_isDisposed) return;

        Stop();
        _capture?.Dispose();
        _cts?.Dispose();
        _isDisposed = true;

        Console.WriteLine("Camera resources released.");
    }
}