﻿#include <array>
#include <cstddef>

#include <DxLib.h>

#include "Shooting/Tuning/GameTuning.h"

#include "Shooting/SoundManager.h"

namespace dxgame::shooting
{
    namespace
    {
        using SoundId = SoundManager::Id;

        // 音声ごとのIdとファイルパスのセット
        struct SoundEntry
        {
            SoundId id;
            const wchar_t* path;
        };

        // Idとファイルパスの対応
        constexpr std::array<SoundEntry, static_cast<std::size_t>(SoundId::Count)> SoundTable =
        {
            SoundEntry { SoundId::TitleBgm, L"Assets/Sounds/TitleBgm.wav" },
            SoundEntry { SoundId::PlayingBgm, L"Assets/Sounds/PlayingBgm.wav" },
            SoundEntry { SoundId::Shot, L"Assets/Sounds/Shot.wav" },
            SoundEntry { SoundId::Hit, L"Assets/Sounds/Hit.wav" },
            SoundEntry { SoundId::Damage, L"Assets/Sounds/Damage.wav" },
            SoundEntry { SoundId::Clear, L"Assets/Sounds/Clear.wav" },
            SoundEntry { SoundId::GameOver, L"Assets/Sounds/GameOver.wav" }
        };

        // Idをhandlesの添字へ変換する
        std::size_t ToIndex(SoundId id)
        {
            return static_cast<std::size_t>(id);
        }
    }

    SoundManager::SoundManager()
    {
        // -1はDXライブラリのハンドルをまだ取得していない状態を表す
        handles.fill(-1);
    }

    SoundManager::~SoundManager()
    {
        Release();
    }

    SoundManager::LoadResult SoundManager::LoadAll()
    {
        for (const SoundEntry& entry : SoundTable)
        {
            std::size_t index = ToIndex(entry.id);
            handles[index] = LoadSoundMem(entry.path);

            // 途中で失敗した場合は、ここで読み込み済み音声を解放する
            if (handles[index] == -1)
            {
                Release();
                return { false, entry.path };
            }

            // BGMとSEで共通の対応表を使いIdから音量を選ぶ
            bool isBgm = entry.id == SoundId::TitleBgm || entry.id == SoundId::PlayingBgm;
            int volume = isBgm ? tuning::sound::BgmVolume : tuning::sound::SeVolume;
            ChangeVolumeSoundMem(volume, handles[index]);
        }
        return { true, {} };
    }

    void SoundManager::PlayBgm(Id id)
    {
        // BGMは同時に1曲だけ再生する
        StopBgm();
        currentBgm = handles[ToIndex(id)];
        PlaySoundMem(currentBgm, DX_PLAYTYPE_LOOP);
    }

    void SoundManager::StopBgm()
    {
        if (currentBgm == -1)
            return;

        StopSoundMem(currentBgm);
        currentBgm = -1;
    }

    void SoundManager::PlaySe(Id id) const
    {
        PlaySoundMem(handles[ToIndex(id)], DX_PLAYTYPE_BACK);
    }

    void SoundManager::Release()
    {
        StopBgm();

        // 解放後は再び呼ばれても処理しないよう-1へ戻す
        for (int& handle : handles)
        {
            if (handle == -1)
                continue;

            DeleteSoundMem(handle);
            handle = -1;
        }
    }
}
