#pragma once
#include "AudioBuffer/AudioBuffer.h"
#include "CoreMinimal.h"

class FMixerChannelNode;
class FMixerTrack;
class FPluginHost;

DECLARE_LOG_CATEGORY_EXTERN(LogMixerTrack, Log, All);

enum class EMixerTrackType
{
	Null,
	Dummy,
	Instrument,
};

struct FMixerTrackLink
{
	FMixerTrack* Track;
	float Gain;
	FMixerTrackLink() : Track(nullptr), Gain(1.f) {}
	FMixerTrackLink(const FMixerTrackLink& Other) : Track(Other.Track), Gain(Other.Gain) {}
	FMixerTrackLink(FMixerTrackLink&& Other) noexcept : Track(Other.Track), Gain(Other.Gain) { Other.Track = nullptr; }
	FMixerTrackLink& operator=(const FMixerTrackLink& Other) { Track = Other.Track; Gain = Other.Gain; return *this; }
};

class FMixerTrack
{
	friend class FThreadMessage_AddEffectToTrack;
public:
	virtual ~FMixerTrack();
	void Init(); 
	void AddEffect(FPluginHost* Effect);
	void RemoveEffect(FPluginHost* Effect);
	void RemoveChild(FMixerTrack* Child);
	
	float** GetBufferHeaders() { return Buffer.GetHeaders(); }

	void Process(int32 NumSamples);

	virtual void Rename(FString InStr) {}
	virtual FString GetName() const { return ""; }

	float GetPeak(int32 Channel) { return Buffer.GetPeak(Channel) * Gain; }

	FChannelInterface const* GetChannelInterface() const { return ChannelInterface; }
	
	std::atomic<float> Gain = 1.f; // dB
	FAudioBuffer Buffer;
	TArray<FPluginHost*> Effects;
	TArray<FMixerTrackLink> Children;
	EMixerTrackType Type;
private:
	void AddEffectInternal(FPluginHost* Effect);

	FChannelInterface* ChannelInterface;
};

class FDummyMixerTrack : public FMixerTrack
{
public:
	FDummyMixerTrack()
	{
		Type = EMixerTrackType::Dummy;
	}
	virtual ~FDummyMixerTrack() override;
	virtual void Rename(FString InStr) override { Name = InStr; }
	virtual FString GetName() const override { return Name; }
private:
	FString Name;
};

class FInstrumentMixerTrack : public FMixerTrack
{
public:
	FInstrumentMixerTrack(FPluginHost* InHost) : Host(InHost)
	{
		Type = EMixerTrackType::Instrument;
	}
	virtual ~FInstrumentMixerTrack() override;
	
	virtual void Rename(FString InStr) override;
	virtual FString GetName() const override;

	FPluginHost* GetHost() const { return Host; }
private:
	FPluginHost* Host;
};