#include "LayerManager.h"
#include "../utils/Logger.h"
#include <pxr/usd/sdf/layer.h>
#include <pxr/usd/sdf/layerUtils.h>
#include <filesystem>

PXR_NAMESPACE_USING_DIRECTIVE

namespace UsdLayerManager {

LayerManager::LayerManager()
    : m_stage(nullptr) {
}

LayerManager::~LayerManager() {
}

void LayerManager::SetStage(UsdStageRefPtr stage) {
    m_stage = stage;
    Refresh();
}

void LayerManager::Refresh() {
    BuildLayerList();
}

std::vector<LayerInfo> LayerManager::GetLayerStack() const {
    return m_layers;
}

std::vector<LayerInfo> LayerManager::GetSublayers() const {
    std::vector<LayerInfo> sublayers;
    if (!m_stage) return sublayers;
    
    SdfLayerHandle rootLayer = m_stage->GetRootLayer();
    if (!rootLayer) return sublayers;
    
    for (const auto& info : m_layers) {
        if (!info.isRootLayer && !info.isSessionLayer) {
            sublayers.push_back(info);
        }
    }
    
    return sublayers;
}

bool LayerManager::CreateSublayer(const std::string& identifier, int index) {
    if (!m_stage) {
        LOG_ERROR("No stage to create sublayer on");
        return false;
    }
    
    SdfLayerHandle rootLayer = m_stage->GetRootLayer();
    if (!rootLayer) {
        LOG_ERROR("No root layer to add sublayer to");
        return false;
    }
    
    try {
        LOG_INFO("Creating sublayer: " + identifier);
        rootLayer->InsertSubLayerPath(identifier, index);
        Refresh();
        return true;
    } catch (const std::exception& e) {
        LOG_ERROR(std::string("Failed to create sublayer: ") + e.what());
        return false;
    }
}

bool LayerManager::InsertSublayerPath(const std::string& path, int index) {
    return CreateSublayer(path, index);
}

bool LayerManager::RemoveSublayer(int index) {
    if (!m_stage) return false;
    
    SdfLayerHandle rootLayer = m_stage->GetRootLayer();
    if (!rootLayer) return false;
    
    try {
        SdfSubLayerProxy sublayers = rootLayer->GetSubLayerPaths();
        if (index < 0 || static_cast<size_t>(index) >= sublayers.size()) {
            LOG_ERROR("Sublayer index out of range");
            return false;
        }
        
        LOG_INFO("Removing sublayer at index: " + std::to_string(index));
        sublayers.erase(sublayers.begin() + index);
        Refresh();
        return true;
    } catch (const std::exception& e) {
        LOG_ERROR(std::string("Failed to remove sublayer: ") + e.what());
        return false;
    }
}

bool LayerManager::MoveSublayerUp(int index) {
    if (index <= 0) return false;
    
    SdfLayerHandle rootLayer = m_stage->GetRootLayer();
    if (!rootLayer) return false;
    
    try {
        SdfSubLayerProxy sublayers = rootLayer->GetSubLayerPaths();
        if (static_cast<size_t>(index) >= sublayers.size()) return false;
        
        std::string temp = sublayers[index];
        sublayers[index] = sublayers[index - 1];
        sublayers[index - 1] = temp;
        Refresh();
        return true;
    } catch (const std::exception& e) {
        LOG_ERROR(std::string("Failed to move sublayer: ") + e.what());
        return false;
    }
}

bool LayerManager::MoveSublayerDown(int index) {
    SdfLayerHandle rootLayer = m_stage->GetRootLayer();
    if (!rootLayer) return false;
    
    try {
        SdfSubLayerProxy sublayers = rootLayer->GetSubLayerPaths();
        if (index < 0 || static_cast<size_t>(index + 1) >= sublayers.size()) return false;
        
        std::string temp = sublayers[index];
        sublayers[index] = sublayers[index + 1];
        sublayers[index + 1] = temp;
        Refresh();
        return true;
    } catch (const std::exception& e) {
        LOG_ERROR(std::string("Failed to move sublayer: ") + e.what());
        return false;
    }
}

void LayerManager::MuteLayer(const std::string& layerIdentifier) {
    if (m_stage) {
        m_stage->MuteLayer(layerIdentifier);
        Refresh();
    }
}

void LayerManager::UnmuteLayer(const std::string& layerIdentifier) {
    if (m_stage) {
        m_stage->UnmuteLayer(layerIdentifier);
        Refresh();
    }
}

bool LayerManager::SetEditTarget(const std::string& identifier) {
    if (!m_stage) return false;
    SdfLayerHandle layer = SdfLayer::Find(identifier);
    if (!layer) return false;
    m_stage->SetEditTarget(layer);
    Refresh();
    return true;
}

bool LayerManager::CreateNewSublayer(const std::string& absolutePath) {
    if (!m_stage) return false;
    SdfLayerHandle rootLayer = m_stage->GetRootLayer();
    if (!rootLayer) return false;

    auto newLayer = SdfLayer::CreateNew(absolutePath);
    if (!newLayer) {
        LOG_ERROR("Failed to create layer file: " + absolutePath);
        return false;
    }
    newLayer->Save();

    rootLayer->InsertSubLayerPath(absolutePath, 0);
    m_stage->SetEditTarget(newLayer);
    Refresh();
    return true;
}

bool LayerManager::IsLayerMuted(const std::string& layerIdentifier) const {
    if (m_stage) {
        return m_stage->IsLayerMuted(layerIdentifier);
    }
    return false;
}

std::string LayerManager::ExtractDisplayName(const std::string& identifier) {
    // Try to extract a user-friendly name from the identifier
    
    // For file paths, use the filename
    std::filesystem::path path(identifier);
    if (path.has_filename()) {
        std::string filename = path.filename().string();
        if (!filename.empty()) {
            return filename;
        }
    }
    
    // For anonymous layers or other identifiers, return a short representation
    if (identifier.find("anon:") == 0) {
        return "Anonymous Layer";
    }
    
    if (identifier.find("session:") == 0) {
        return "Session Layer";
    }
    
    return identifier;
}

void LayerManager::BuildLayerList() {
    m_layers.clear();
    m_layerRefs.clear();
    if (!m_stage) return;

    try {
        SdfLayerHandle rootLayer    = m_stage->GetRootLayer();
        SdfLayerHandle sessionLayer = m_stage->GetSessionLayer();
        SdfLayerHandle editTarget   = m_stage->GetEditTarget().GetLayer();

        auto makeInfo = [&](SdfLayerHandle layer, bool isRoot, bool isSession) {
            LayerInfo info;
            info.layer          = layer;
            info.identifier     = layer->GetIdentifier();
            info.displayName    = ExtractDisplayName(info.identifier);
            info.realPath       = layer->GetRealPath();
            info.isMuted        = m_stage->IsLayerMuted(info.identifier);
            info.isAnonymous    = layer->IsAnonymous();
            info.isRootLayer    = isRoot;
            info.isSessionLayer = isSession;
            info.isEditTarget   = (layer == editTarget);
            info.isDirty        = layer->IsDirty();
            return info;
        };

        // Root and session layers: stage always holds strong refs, handles are valid.
        if (sessionLayer) m_layers.push_back(makeInfo(sessionLayer, false, true));
        if (rootLayer)    m_layers.push_back(makeInfo(rootLayer,    true,  false));

        // Walk root layer's sublayer paths instead of stage->GetLayerStack().
        // GetLayerStack() drops muted layers because they don't contribute to
        // composition. FindOrOpenRelativeToLayer locates or reopens the layer
        // regardless of mute state. We store the returned RefPtr in m_layerRefs
        // so the layer object isn't garbage-collected before the next Refresh().
        if (rootLayer) {
            for (const auto& subPath : rootLayer->GetSubLayerPaths()) {
                SdfLayerRefPtr subRef =
                    SdfLayer::FindOrOpenRelativeToLayer(rootLayer, subPath);
                if (subRef) {
                    m_layerRefs.push_back(subRef);
                    m_layers.push_back(makeInfo(SdfLayerHandle(subRef), false, false));
                }
            }
        }

        LOG_DEBUG("Built layer list with " + std::to_string(m_layers.size()) + " layers");

    } catch (const std::exception& e) {
        LOG_ERROR(std::string("Failed to build layer list: ") + e.what());
    }
}

} // namespace UsdLayerManager