/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 * For complete copyright and license terms please see the LICENSE at the root of this distribution.
 *
 * SPDX-License-Identifier: Apache-2.0 OR MIT
 *
 */

#pragma once

#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/string/string.h>

#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabInMemorySpawnableConverter.h>

namespace AzToolsFramework
{
    namespace Prefab
    {
        //! A RootAliasPath can be used to store an alias path that starts from the Prefab EOS root instance.
        //! The root instance itself is included in the path. These can be used as Instance handles across systems
        //! that do not have visibility over InstanceOptionalReferences, or that need to store Instance handles
        //! for longer than just the span of a function without the risk of them going out of scope.
        using RootAliasPath = AliasPath;
    }

    enum class GameModeState
    {
        Started,
        Stopped
    };

    class PrefabEditorEntityOwnershipInterface
    {
    public:
        AZ_RTTI(PrefabEditorEntityOwnershipInterface, "{38E764BA-A089-49F3-848F-46018822CE2E}");

        //! Returns whether the system has a root instance assigned.
        //! @return True if a root prefab is assigned, false otherwise.
        virtual bool IsRootPrefabAssigned() const = 0;

        //! Returns an optional reference to the root prefab instance.
        virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;

        //! Returns the template id for the root prefab instance.
        virtual Prefab::TemplateId GetRootPrefabTemplateId() = 0;

        virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0;

        //! Creates a prefab instance with the provided entities and nestedPrefabInstances.
        //! @param entities The entities to put under the new prefab.
        //! @param nestedPrefabInstances The nested prefab instances to put under the new prefab.
        //! @param filePath The filepath corresponding to the prefab file to be created.
        //! @param instanceToParentUnder The instance the newly created prefab instance is parented under.
        //! @return The optional reference to the prefab created.
        virtual Prefab::InstanceOptionalReference CreatePrefab(
            const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
            AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0;

        //! Instantiate the prefab file provided.
        //! @param filePath The filepath for the prefab file the instance should be created from.
        //! @param instanceToParentUnder The instance the newly instantiated prefab instance is parented under.
        //! @return The optional reference to the prefab instance.
        virtual Prefab::InstanceOptionalReference InstantiatePrefab(
            AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0;

        virtual void StartPlayInEditor() = 0;
        virtual void StopPlayInEditor() = 0;

        //! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G)
        //! @return The vector of Assets generated by Prefab processing
        virtual const AzFramework::InMemorySpawnableAssetContainer::SpawnableAssets& GetPlayInEditorAssetData() const = 0;

        virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
        virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;

        //! Returns the reference to the instance corresponding to the RootAliasPath provided.
        //! @param rootAliasPath The RootAliasPath to be queried.
        //! @return A reference to the instance if valid, AZStd::nullopt otherwise.
        virtual Prefab::InstanceOptionalReference GetInstanceReferenceFromRootAliasPath(Prefab::RootAliasPath rootAliasPath) const = 0;

        //! Allows to iterate through all instances referenced in the path, from the root down.
        //! @param rootAliasPath The RootAliasPath to iterate through. If invalid, callback will not be called.
        //! @param callback The function to call on each instance. If it returns true, it prevents the rest of the path from being called.
        //! @return True if the iteration was halted by a callback returning true, false otherwise. Also returns false if the path is invalid.
        virtual bool GetInstancesInRootAliasPath(
            Prefab::RootAliasPath rootAliasPath, const AZStd::function<bool(const Prefab::InstanceOptionalReference)>& callback) const = 0;

        virtual void RegisterGameModeEventHandler(AZ::Event<GameModeState>::Handler& handler) = 0;
    };
}
