// PRE-GENERATED (design session). Windows output-device volume via NAudio Core Audio.
// Syncs BOTH ways: app slider -> endpoint volume, and Windows volume change -> app (event).
// Requires NuGet: NAudio. Untested here.
using System;
using System.Collections.Generic;
using NAudio.CoreAudioApi;

namespace DansoriEQ.App.Audio;

public sealed class AudioDevice
{
    public string Id { get; init; } = "";
    public string Name { get; init; } = "";
    public bool IsDefault { get; init; }
    public override string ToString() => Name;
}

public sealed class SystemVolumeService : IDisposable
{
    private readonly MMDeviceEnumerator _enum = new();
    private MMDevice? _current;

    /// <summary>(scalar 0..1, muted) — raised when the selected device's volume changes (incl. from Windows).</summary>
    public event Action<float, bool>? VolumeChanged;

    public IReadOnlyList<AudioDevice> GetOutputDevices()
    {
        var list = new List<AudioDevice>();
        string? defId = null;
        try { defId = _enum.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia).ID; } catch { }
        foreach (var d in _enum.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active))
            list.Add(new AudioDevice { Id = d.ID, Name = d.FriendlyName, IsDefault = d.ID == defId });
        return list;
    }

    public void Select(string deviceId)
    {
        Detach();
        _current = _enum.GetDevice(deviceId);
        _current.AudioEndpointVolume.OnVolumeNotification += OnNotify;
    }

    public float GetVolume() => _current?.AudioEndpointVolume.MasterVolumeLevelScalar ?? 0f;
    public bool GetMute() => _current?.AudioEndpointVolume.Mute ?? false;

    public void SetVolume(float scalar)
    {
        if (_current == null) return;
        _current.AudioEndpointVolume.MasterVolumeLevelScalar = Math.Clamp(scalar, 0f, 1f);
    }

    public void SetMute(bool mute)
    {
        if (_current != null) _current.AudioEndpointVolume.Mute = mute;
    }

    private void OnNotify(AudioVolumeNotificationData data)
        => VolumeChanged?.Invoke(data.MasterVolume, data.Muted);   // fires on a non-UI thread

    private void Detach()
    {
        if (_current == null) return;
        try { _current.AudioEndpointVolume.OnVolumeNotification -= OnNotify; } catch { }
        _current.Dispose();
        _current = null;
    }

    public void Dispose()
    {
        Detach();
        _enum.Dispose();
    }
}
