/*******************************************************************************
 *
 * MIT License
 *
 * Copyright 2024-2025 AMD ROCm(TM) Software
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#pragma once

#include "KernelOptions_fwd.hpp"

#include <memory>
#include <ostream>
#include <string>

#include <rocRoller/AssertOpKinds_fwd.hpp>
#include <rocRoller/Operations/Scratch_fwd.hpp>
#include <rocRoller/Utilities/EnumBitset.hpp>
#include <rocRoller/Utilities/Settings_fwd.hpp>

namespace rocRoller
{
    const std::string XLOOP   = "XLoop";
    const std::string YLOOP   = "YLoop";
    const std::string KLOOP   = "KLoop";
    const std::string RECEIVE = "ReceiveTileLoop";

    const int XLOOP_UNROLL = 0;
    const int YLOOP_UNROLL = 1;
    const int KLOOP_UNROLL = 2;

    const std::string KLOOPTAIL = KLOOP + "Tail";

    const std::string SCRATCH = "SCRATCH";
    const std::string NUMWGS  = "numWGs";
    const std::string WGM     = "WGM";

    // Helper to get scratch argument name for a specific policy
    inline std::string getScratchName(Operations::ScratchPolicy policy)
    {
        return rocRoller::SCRATCH + "_" + Operations::toString(policy);
    }

    class KernelOptions
    {
    public:
        KernelOptions();
        // cppcheck-suppress noExplicitConstructor
        KernelOptions(KernelOptionValues&& other);

        KernelOptions(KernelOptions const& other);
        KernelOptions(KernelOptions&& other);

        KernelOptions& operator=(KernelOptions const& other);
        KernelOptions& operator=(KernelOptions&& other);

        KernelOptions& operator=(KernelOptionValues const& other);
        KernelOptions& operator=(KernelOptionValues&& other);

        ~KernelOptions();

        KernelOptionValues* operator->();
        KernelOptionValues& operator*();

        KernelOptionValues const* operator->() const;
        KernelOptionValues const& operator*() const;

        std::string          toString() const;
        friend std::ostream& operator<<(std::ostream&, const KernelOptions&);

    private:
        std::unique_ptr<KernelOptionValues> m_values;
    };
}
