local task = require "lib.utils.task"
local ease = require "lib.utils.easing"

local EFFECTS_SUPPORTED = love.audio.isEffectsSupported()

--- @alias SourceFilter { type: "bandpass"|"highpass"|"lowpass", volume: number, highgain: number, lowgain: number }

--- @class Audio
--- @field musicVolume number
--- @field soundVolume number
--- @field looped boolean
--- @field from love.Source?
--- @field to love.Source?
audio = {}
audio.__index = audio

--- здесь мы должны выгружать значения из файлика с сохранением настроек
local function new(musicVolume, soundVolume)
    return setmetatable({
        musicVolume = musicVolume,
        soundVolume = soundVolume,
        looped = true
    }, audio)
end

function audio:update(dt)
    if self.fader then
        local t = self.fader.value
        if self.from then self.from:setVolume(self.musicVolume * (1 - t)) end
        if self.to then self.to:setVolume(self.musicVolume * t) end
    end
end

--- if from is nil, than we have fade in to;
--- if to is nil, than we have fade out from
---
--- also we should guarantee, that from and to have the same volume
--- @param from love.Source
--- @param to love.Source
--- @param ms number? in milliseconds
function audio:crossfade(from, to, ms)
    print("[Audio]: Triggered crossfade")

    -- Stop previous 'from' if it's dangling to avoid leaks
    if self.from and self.from ~= from and self.from ~= to then
        self.from:stop()
    end

    self:play(to)
    to:setVolume(0)
    self.from = from
    self.to = to

    -- Reuse fader object to allow task cancellation
    if not self.fader then self.fader = { value = 0 } end
    self.fader.value = 0

    task.tween(self.fader, { value = 1 }, ms or 1000, ease.easeOutCubic)(function()
        if self.from then
            self.from:setVolume(0)
            self.from:stop()
        end
        if self.to then
            self.to:setVolume(self.musicVolume)
        end
        self.fader = nil
        print("[Audio]: Crossfade done")
    end)
end

--- @param source love.Source
--- @param settings SourceFilter?
--- @param effectName string?
function audio:play(source, settings, effectName)
    if source:getType() == "stream" then
        source:setLooping(self.looped)
        source:setVolume(self.musicVolume)
        source:play()
    else
        source:setVolume(self.soundVolume)
        source:play()
    end
    if settings and EFFECTS_SUPPORTED then
        source.setFilter(source, settings)
    end
    if effectName and EFFECTS_SUPPORTED then
        source:setEffect(effectName, true)
    end
end

function audio:setMusicVolume(volume)
    self.musicVolume = volume
end

function audio:setSoundVolume(volume)
    self.soundVolume = volume
end

return { new = new }
