using Grpc.Core;
using GeViScopeBridge.Protos;
using GeViScopeBridge.SDK;
using GeViScopeBridge.Utils;
using Serilog;

namespace GeViScopeBridge.Services
{
    /// <summary>
    /// gRPC service for monitor (video output) operations
    /// </summary>
    public class MonitorServiceImplementation : MonitorService.MonitorServiceBase
    {
        private readonly StateQueryHandler _stateQuery;
        private readonly ILogger _logger;

        public MonitorServiceImplementation(StateQueryHandler stateQuery, ILogger logger)
        {
            _stateQuery = stateQuery ?? throw new ArgumentNullException(nameof(stateQuery));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// List all monitors/viewers (video outputs)
        /// </summary>
        public override async Task<ListMonitorsResponse> ListMonitors(
            ListMonitorsRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("ListMonitors called");

                var monitors = await _stateQuery.EnumerateMonitorsAsync();

                var response = new ListMonitorsResponse
                {
                    TotalCount = monitors.Count
                };

                foreach (var monitor in monitors)
                {
                    response.Monitors.Add(new MonitorInfo
                    {
                        Id = monitor.Id,
                        Name = monitor.Name,
                        Description = monitor.Description,
                        IsActive = monitor.IsActive,
                        CurrentCameraId = monitor.CurrentCameraId,
                        Status = monitor.Status,
                        LastUpdated = new Timestamp
                        {
                            Seconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                            Nanos = 0
                        }
                    });
                }

                _logger.Information("ListMonitors completed: {Count} monitors", monitors.Count);
                return response;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Failed to list monitors");
                throw ErrorTranslator.CreateRpcException(ex, "Failed to list monitors");
            }
        }

        /// <summary>
        /// Get detailed information about a specific monitor
        /// </summary>
        public override async Task<MonitorInfo> GetMonitor(
            GetMonitorRequest request,
            ServerCallContext context)
        {
            try
            {
                _logger.Information("GetMonitor called for monitor {MonitorId}", request.MonitorId);

                // Enumerate all monitors and find the requested one
                var monitors = await _stateQuery.EnumerateMonitorsAsync();
                var monitor = monitors.FirstOrDefault(m => m.Id == request.MonitorId);

                if (monitor == null)
                {
                    throw new RpcException(new Status(StatusCode.NotFound,
                        $"Monitor with ID {request.MonitorId} not found"));
                }

                var response = new MonitorInfo
                {
                    Id = monitor.Id,
                    Name = monitor.Name,
                    Description = monitor.Description,
                    IsActive = monitor.IsActive,
                    CurrentCameraId = monitor.CurrentCameraId,
                    Status = monitor.Status,
                    LastUpdated = new Timestamp
                    {
                        Seconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                        Nanos = 0
                    }
                };

                _logger.Information("GetMonitor completed for monitor {MonitorId}", request.MonitorId);
                return response;
            }
            catch (RpcException)
            {
                throw;  // Re-throw RpcExceptions as-is
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Failed to get monitor {MonitorId}", request.MonitorId);
                throw ErrorTranslator.CreateRpcException(ex, "Failed to get monitor");
            }
        }
    }
}
