#include "AssetListReader.h"

#include "Csv/CsvStream.h"
#include "Game/IGame.h"
#include "Utils/Logging/Log.h"

#include <format>

namespace
{
    class AssetListInputStream
    {
    public:
        AssetListInputStream(std::istream& stream, const GameId gameId)
            : m_stream(stream),
              m_game(*IGame::GetGameById(gameId))
        {
        }

        bool NextEntry(AssetListEntry& entry, bool* failure) const
        {
            std::vector<std::string> row;
            if (failure)
                *failure = false;

            while (true)
            {
                if (!m_stream.NextRow(row))
                    return false;

                if (row.empty() || (row.size() == 1 && row[0].empty()))
                    continue;

                const auto& typeName = row[0];
                const auto maybeType = m_game.FindAssetTypeByName(typeName);
                if (!maybeType)
                {
                    con::error("Unknown asset type name \"{}\"", typeName);
                    if (failure)
                        *failure = true;
                    return false;
                }

                entry.m_type = *maybeType;
                if (row.size() >= 3 && row[1].empty())
                {
                    entry.m_name = row[2];
                    entry.m_is_reference = true;
                }
                else
                {
                    entry.m_name = row[1];
                    entry.m_is_reference = false;
                }

                return true;
            }
        }

    private:
        CsvInputStream m_stream;
        IGame& m_game;
    };
} // namespace

AssetListReader::AssetListReader(ISearchPath& searchPath, const GameId game)
    : m_search_path(searchPath),
      m_game(game)
{
}

std::optional<AssetList> AssetListReader::ReadAssetList(const std::string& zoneName, const bool logMissing) const
{
    const auto assetListFileName = std::format("assetlist/{}.csv", zoneName);
    const auto assetListStream = m_search_path.Open(assetListFileName);

    if (assetListStream.IsOpen())
    {
        AssetList assetList;
        const AssetListInputStream stream(*assetListStream.m_stream, m_game);
        AssetListEntry entry;

        bool failure;
        while (stream.NextEntry(entry, &failure))
        {
            assetList.m_entries.emplace_back(std::move(entry));
        }

        if (!failure)
            return assetList;
    }
    else if (logMissing)
        con::error("Failed to open file for assetlist: {}", assetListFileName);

    return std::nullopt;
}
