using System;
using System.Threading;
using System.Threading.Tasks;
using FootwearTest.Models;
using Microsoft.Extensions.Logging;

namespace FootwearTest.Services;

public sealed class SimulatedDeviceClient : IDeviceClient
{
    private readonly DeviceSettings _settings;
    private readonly ILogger<SimulatedDeviceClient> _logger;
    private readonly Random _random = new();
    private bool _pumpRunning;
    private bool _fanRunning;
    private bool _heaterRunning;
    private double _energyKilojoules;

    public SimulatedDeviceClient(DeviceSettings settings, ILogger<SimulatedDeviceClient> logger)
    {
        _settings = settings;
        _logger = logger;
        LastSnapshot = DeviceSnapshot.Initial;
    }

    public bool IsConnected { get; private set; }
    public string ConnectionText => IsConnected ? "模拟器已连接" : "未连接";
    public DeviceSnapshot LastSnapshot { get; private set; }
    public event EventHandler<DeviceSnapshot>? SnapshotUpdated;

    public Task ConnectAsync(CancellationToken cancellationToken = default)
    {
        IsConnected = true;
        _logger.LogInformation("Simulator connected. PollIntervalMs={PollIntervalMs}", _settings.PollIntervalMilliseconds);
        return ReadSnapshotAsync(cancellationToken);
    }

    public Task DisconnectAsync(CancellationToken cancellationToken = default)
    {
        if (IsConnected)
        {
            _logger.LogInformation("Simulator disconnected");
        }

        IsConnected = false;
        _pumpRunning = false;
        _fanRunning = false;
        _heaterRunning = false;
        return Task.CompletedTask;
    }

    public Task SetOutputsAsync(bool pumpRunning, bool fanRunning, bool heaterRunning, CancellationToken cancellationToken = default)
    {
        _pumpRunning = pumpRunning;
        _fanRunning = fanRunning;
        _heaterRunning = heaterRunning;
        _logger.LogInformation(
            "Simulator outputs changed. Pump={PumpRunning}, Fan={FanRunning}, Heater={HeaterRunning}",
            pumpRunning,
            fanRunning,
            heaterRunning);
        return ReadSnapshotAsync(cancellationToken);
    }

    public Task<DeviceSnapshot> ReadSnapshotAsync(CancellationToken cancellationToken = default)
    {
        var targetFoot = _heaterRunning ? _settings.MethodATargetTemperatureC : _settings.EnvironmentTemperatureC;
        var previous = LastSnapshot;
        var foot = previous.FootTemperatureC + (targetFoot - previous.FootTemperatureC) * 0.18 + Noise(0.08);
        var chamber = _settings.EnvironmentTemperatureC + Noise(0.12);
        var humidity = _settings.EnvironmentHumidityPercent + Noise(0.35);
        var airSpeed = (_fanRunning ? _settings.MethodBAirSpeedMetersPerSecond : 0.05) + Noise(0.03);
        var waterLoss = _pumpRunning ? _settings.PumpSpeedCubicCentimetersPerHour + Noise(0.12) : Math.Max(0, Noise(0.03));
        var power = _heaterRunning ? 4.2 + Math.Max(0, targetFoot - chamber) * 0.03 + Noise(0.12) : 0.0;

        _energyKilojoules += power * _settings.PollIntervalMilliseconds / 1_000_000.0;
        LastSnapshot = new DeviceSnapshot(
            DateTime.Now,
            Math.Round(foot, 2),
            Math.Round(chamber, 2),
            Math.Round(humidity, 2),
            Math.Round(Math.Max(0, airSpeed), 2),
            Math.Round(Math.Max(0, power), 2),
            Math.Round(_energyKilojoules, 3),
            Math.Round(Math.Max(0, waterLoss), 2),
            _settings.PumpSpeedCubicCentimetersPerHour,
            _pumpRunning,
            _fanRunning,
            _heaterRunning,
            "无报警");

        SnapshotUpdated?.Invoke(this, LastSnapshot);
        return Task.FromResult(LastSnapshot);
    }

    private double Noise(double amplitude) => (_random.NextDouble() * 2.0 - 1.0) * amplitude;
}
