// SPDX-FileCopyrightText: 2024 Open Mobile Platform LLC <community@omp.ru>
// SPDX-License-Identifier: BSD-3-Clause

#include <QCoreApplication>

#include "earpieceplayer.h"

/*!
 * \brief Constructor initializes and sets up the audio resource.
 * \param parent QObject parent instance.
 */
EarpiecePlayer::EarpiecePlayer(QObject *parent) : QObject(parent) { }

/*!
 * \brief Destrustor stops playing an audio file and releases the audio resource.
 */
EarpiecePlayer::~EarpiecePlayer()
{
    releaseAudioResource();
}

bool EarpiecePlayer::resourceGranted() const
{
    return m_resourceGranted;
}

void EarpiecePlayer::grantAudioResource()
{
    ResourcePolicy::AudioResource *audioResource = createAudioResource();
    m_resourceSet = QSharedPointer<ResourcePolicy::ResourceSet>(
            new ResourcePolicy::ResourceSet("call", this, true, true));
    m_resourceSet->addResourceObject(audioResource);
    setupResourceSetHandlers();
    m_resourceSet->initAndConnect();
}

/*!
 * \brief Stops playing an audio file and releases the audio resource.
 */
void EarpiecePlayer::releaseAudioResource()
{
    stop();
    if (m_resourceSet != nullptr && m_resourceGranted)
        m_resourceSet->release();
}

/*!
 * \brief Plays an audio by the given URI using QMediaPlayer.
 * \param audioFilePath Audio file URI to play.
 */
void EarpiecePlayer::play(const QString &audioFileUri)
{
    m_player = QSharedPointer<QMediaPlayer>(new QMediaPlayer(this));
    connect(m_player.data(),
            static_cast<void (QMediaPlayer::*)(QMediaPlayer::Error)>(&QMediaPlayer::error), this,
            &EarpiecePlayer::handleMediaPlayerError);
    connect(m_player.data(), &QMediaPlayer::mediaStatusChanged, this,
            &EarpiecePlayer::handleMediaPlayerStatusChanged);
    m_player->setAudioRole(QAudio::VoiceCommunicationRole);
    m_player->setMedia(QUrl(audioFileUri));
    m_player->play();
}

/*!
 * \brief Stops playing the current audio file.
 */
void EarpiecePlayer::stop()
{
    if (m_player->state() == QMediaPlayer::PlayingState
        || m_player->state() == QMediaPlayer::PausedState)
        m_player->stop();
}

/*!
 * \brief Creates the ResourcePolicy::AudioResource instance with the current selected audio group.
 * \return ResourcePolicy::AudioResource pointer.
 */
ResourcePolicy::AudioResource *EarpiecePlayer::createAudioResource()
{
    ResourcePolicy::AudioResource *audioResource = new ResourcePolicy::AudioResource("call");
    audioResource->setProcessID(QCoreApplication::applicationPid());
    audioResource->setStreamTag("media.name", "*");
    return audioResource;
}

/*!
 * \brief Sets up the resource set signal handlers.
 * Signals: resourcesBecameAvailable(), resourcesGranted(), resourcesReleased().
 */
void EarpiecePlayer::setupResourceSetHandlers()
{
    connect(m_resourceSet.data(), &ResourcePolicy::ResourceSet::resourcesBecameAvailable, this,
            &EarpiecePlayer::acquireAudioResource);
    connect(m_resourceSet.data(), &ResourcePolicy::ResourceSet::resourcesGranted, this,
            &EarpiecePlayer::handleAudioResourceGranted);
    connect(m_resourceSet.data(), &ResourcePolicy::ResourceSet::resourcesReleased, this,
            &EarpiecePlayer::handleAudioResourceReleased);
    connect(m_resourceSet.data(), &ResourcePolicy::ResourceSet::resourcesDenied, this,
            &EarpiecePlayer::handleAudioResourceDenied);
}

void EarpiecePlayer::setResourceGranted(const bool granted)
{
    m_resourceGranted = granted;
    emit resourceGrantedChanged();
}

/*!
 * \brief Handles the media player instance error.
 * This method prints an error into logs.
 * \param error Error of the media player.
 */
void EarpiecePlayer::handleMediaPlayerError(QMediaPlayer::Error error)
{
    qInfo() << QStringLiteral("MediaPlayer error: %1").arg(error);
    emit playingFinished();
}

/*!
 * \brief Handles the media player instance status changing.
 * This methods runs playing again if it's finished.
 * \param status New status of the media player.
 */
void EarpiecePlayer::handleMediaPlayerStatusChanged(QMediaPlayer::MediaStatus status)
{
    if (status == QMediaPlayer::EndOfMedia)
        m_player->play();
}

/*!
 * \brief Acquires an audio resource to grant.
 */
void EarpiecePlayer::acquireAudioResource()
{
    qInfo() << "Audio resource became available";
    m_resourceSet->acquire();
}

/*!
 * \brief Sets the 'resourceGranted' peoperty as 'true' and prints a message into logs.
 * This method is called when tha audio resource is granted.
 */
void EarpiecePlayer::handleAudioResourceGranted()
{
    qInfo() << "Audio resource granted";
    setResourceGranted(true);
}

/*!
 * \brief Sets the 'resourceGranted' peoperty as 'false' and prints a message into logs.
 * This method is called when tha audio resource is released.
 */
void EarpiecePlayer::handleAudioResourceReleased()
{
    qInfo() << "Audio resource released";
    setResourceGranted(false);
}

/*!
 * \brief Sets the 'resourceGranted' peoperty as 'false' and prints a message into logs.
 * This method is called when tha audio resource is denied.
 */
void EarpiecePlayer::handleAudioResourceDenied()
{
    qInfo() << "Audio resource denied";
    setResourceGranted(false);
}
