/*
 *   Copyright (c) 2024 Project CHIP Authors
 *   All rights reserved.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

#include "DeviceSynchronization.h"
#include "DeviceManager.h"
#include "DeviceSubscriptionManager.h"

#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/InteractionModelEngine.h>
#include <app/server/Server.h>

using namespace ::chip;
using namespace ::chip::app;
using chip::app::ReadClient;

namespace admin {

namespace {

constexpr uint16_t kBasicInformationAttributeBufSize = 128;

void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
{
    reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle);
}

void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
{
    reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnectionFailure(peerId, error);
}

bool SuccessOrLogName(CHIP_ERROR err, const char * name)
{
    SuccessOrLog(err, NotSpecified, "Failed to read %s", name);
    return (err == CHIP_NO_ERROR);
}

} // namespace

DeviceSynchronizer & DeviceSynchronizer::Instance()
{
    static DeviceSynchronizer instance;
    return instance;
}

DeviceSynchronizer::DeviceSynchronizer() :
    mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this),
    mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this)
{}

void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
{
    VerifyOrDie(path.mEndpointId == kRootEndpointId);
    VerifyOrDie(path.mClusterId == Clusters::BasicInformation::Id);

    if (!status.IsSuccess())
    {
        ChipLogError(NotSpecified, "Response Failure: %" CHIP_ERROR_FORMAT, status.ToChipError().Format());
        return;
    }

    switch (path.mAttributeId)
    {
    case Clusters::BasicInformation::Attributes::UniqueID::Id: {
        char uniqueIdBuffer[kBasicInformationAttributeBufSize];
        if (SuccessOrLogName(data->GetString(uniqueIdBuffer, sizeof(uniqueIdBuffer)), "UniqueId"))
        {
            mCurrentDeviceData.uniqueId = std::string(uniqueIdBuffer);
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::VendorID::Id: {
        uint32_t vendorId;
        if (SuccessOrLogName(data->Get(vendorId), "VendorID"))
        {
            mCurrentDeviceData.vendorId = static_cast<chip::VendorId>(vendorId);
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::VendorName::Id: {
        char vendorNameBuffer[kBasicInformationAttributeBufSize];
        if (SuccessOrLogName(data->GetString(vendorNameBuffer, sizeof(vendorNameBuffer)), "VendorName"))
        {
            mCurrentDeviceData.vendorName = std::string(vendorNameBuffer);
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::ProductID::Id: {
        uint32_t productId;
        if (SuccessOrLogName(data->Get(productId), "ProductID"))
        {
            mCurrentDeviceData.productId = productId;
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::ProductName::Id: {
        char productNameBuffer[kBasicInformationAttributeBufSize];
        if (SuccessOrLogName(data->GetString(productNameBuffer, sizeof(productNameBuffer)), "ProductName"))
        {
            mCurrentDeviceData.productName = std::string(productNameBuffer);
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::NodeLabel::Id: {
        char nodeLabelBuffer[kBasicInformationAttributeBufSize];
        if (SuccessOrLogName(data->GetString(nodeLabelBuffer, sizeof(nodeLabelBuffer)), "NodeLabel"))
        {
            mCurrentDeviceData.nodeLabel = std::string(nodeLabelBuffer);
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::HardwareVersionString::Id: {
        char hardwareVersionStringBuffer[kBasicInformationAttributeBufSize];
        if (SuccessOrLogName(data->GetString(hardwareVersionStringBuffer, sizeof(hardwareVersionStringBuffer)),
                             "HardwareVersionString"))
        {
            mCurrentDeviceData.hardwareVersionString = std::string(hardwareVersionStringBuffer);
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::SoftwareVersion::Id: {
        uint32_t softwareVersion;
        if (SuccessOrLogName(data->Get(softwareVersion), "SoftwareVersion"))
        {
            mCurrentDeviceData.softwareVersion = softwareVersion;
        }
    }
    break;
    case Clusters::BasicInformation::Attributes::SoftwareVersionString::Id: {
        char softwareVersionStringBuffer[kBasicInformationAttributeBufSize];
        if (SuccessOrLogName(data->GetString(softwareVersionStringBuffer, sizeof(softwareVersionStringBuffer)),
                             "SoftwareVersionString"))
        {
            mCurrentDeviceData.softwareVersionString = std::string(softwareVersionStringBuffer);
        }
    }
    break;
    default:
        break;
    }
}

void DeviceSynchronizer::OnReportEnd()
{
    // Report end is at the end of all attributes (success)
    MoveToState(State::ReceivedResponse);
}

void DeviceSynchronizer::OnDone(app::ReadClient * apReadClient)
{
    ChipLogProgress(NotSpecified, "Synchronization complete for NodeId:" ChipLogFormatX64, ChipLogValueX64(mNodeId));

    if (mState == State::ReceivedResponse && !DeviceManager::Instance().IsCurrentBridgeDevice(mNodeId))
    {
        GetUniqueId();
        if (mState == State::GettingUid)
        {
            ChipLogProgress(NotSpecified,
                            "GetUniqueId was successful and we rely on callback to call SynchronizationCompleteAddDevice.");
            return;
        }
        SynchronizationCompleteAddDevice();
    }

    MoveToState(State::Idle);
}

void DeviceSynchronizer::OnError(CHIP_ERROR error)
{
    MoveToState(State::ReceivedError);
    ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
}

void DeviceSynchronizer::OnDeviceConnected(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
{
    mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
                                           *this /* callback */, ReadClient::InteractionType::Read);
    VerifyOrDie(mClient);

    AttributePathParams readPaths[1];
    readPaths[0] = AttributePathParams(kRootEndpointId, Clusters::BasicInformation::Id);

    ReadPrepareParams readParams(sessionHandle);

    readParams.mpAttributePathParamsList    = readPaths;
    readParams.mAttributePathParamsListSize = 1;

    CHIP_ERROR err = mClient->SendRequest(readParams);

    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(NotSpecified, "Failed to issue read for BasicInformation data");
        MoveToState(State::Idle);
    }
    MoveToState(State::AwaitingResponse);
}

void DeviceSynchronizer::OnDeviceConnectionFailure(const ScopedNodeId & peerId, CHIP_ERROR error)
{
    ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
    MoveToState(State::Idle);
}

void DeviceSynchronizer::StartDeviceSynchronization(Controller::DeviceController * controller, NodeId nodeId, bool deviceIsIcd)
{
    VerifyOrDie(controller);
    if (mState != State::Idle)
    {
        ChipLogError(NotSpecified, "Device Sync NOT POSSIBLE: another sync is in progress");
        return;
    }

    mNodeId = nodeId;

    ChipLogProgress(NotSpecified, "Start device synchronization for NodeId:" ChipLogFormatX64, ChipLogValueX64(mNodeId));

    mCurrentDeviceData       = SynchronizedDevice_init_default;
    mCurrentDeviceData.id    = chip::ScopedNodeId(nodeId, controller->GetFabricIndex());
    mCurrentDeviceData.isIcd = deviceIsIcd;

    ReturnOnFailure(controller->GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback));
    mController = controller;
    MoveToState(State::Connecting);
}

void DeviceSynchronizer::GetUniqueId()
{
    VerifyOrDie(mState == State::ReceivedResponse);
    VerifyOrDie(mController);

    // If we have a UniqueId we can return leaving state in ReceivedResponse.
    VerifyOrReturn(!mCurrentDeviceData.uniqueId.has_value(), ChipLogDetail(NotSpecified, "We already have UniqueId"));

    auto * device = DeviceManager::Instance().FindDeviceByNode(mNodeId);
    // If there is no associated remote Fabric Sync Aggregator there is no other place for us to try
    // getting the UniqueId from and can return leaving the state in ReceivedResponse.
    VerifyOrReturn(device, ChipLogDetail(NotSpecified, "No remote Fabric Sync Aggregator to get UniqueId from"));

    // Because device is not-null we expect IsFabricSyncReady to be true. IsFabricSyncReady indicates we have a
    // connection to the remote Fabric Sync Aggregator.
    VerifyOrDie(DeviceManager::Instance().IsFabricSyncReady());
    auto remoteBridgeNodeId               = DeviceManager::Instance().GetRemoteBridgeNodeId();
    EndpointId remoteEndpointIdOfInterest = device->GetEndpointId();

    ChipLogDetail(NotSpecified, "Attempting to get UniqueId from remote Fabric Sync Aggregator");
    CHIP_ERROR err = mUniqueIdGetter.GetUniqueId(
        [this](std::optional<CharSpan> aUniqueId) {
            if (aUniqueId.has_value())
            {
                // Convert CharSpan to std::string and set it as uniqueId
                this->mCurrentDeviceData.uniqueId = std::string(aUniqueId.value().data(), aUniqueId.value().size());
            }
            else
            {
                ChipLogError(NotSpecified, "We expected to get UniqueId from remote Fabric Sync Aggregator, but failed");
            }
            this->SynchronizationCompleteAddDevice();
        },
        *mController, remoteBridgeNodeId, remoteEndpointIdOfInterest);

    if (err == CHIP_NO_ERROR)
    {
        MoveToState(State::GettingUid);
    }
    else
    {
        ChipLogDetail(NotSpecified, "Failed to get UniqueId from remote Fabric Sync Aggregator");
    }
}

void DeviceSynchronizer::SynchronizationCompleteAddDevice()
{
    VerifyOrDie(mState == State::ReceivedResponse || mState == State::GettingUid);
    ChipLogProgress(NotSpecified, "Synchronization complete and add device");

    TEMPORARY_RETURN_IGNORED bridge::FabricBridge::Instance().AddSynchronizedDevice(mCurrentDeviceData);

    // TODO(#35077) Figure out how we should reflect CADMIN values of ICD.
    if (!mCurrentDeviceData.isIcd.value_or(false))
    {
        VerifyOrDie(mController);
        ScopedNodeId scopedNodeId(mNodeId, mController->GetFabricIndex());
        CHIP_ERROR err = DeviceSubscriptionManager::Instance().StartSubscription(*mController, scopedNodeId);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(NotSpecified, "Failed start subscription to NodeId:" ChipLogFormatX64, ChipLogValueX64(mNodeId));
            TEMPORARY_RETURN_IGNORED bridge::FabricBridge::Instance().DeviceReachableChanged(mCurrentDeviceData.id, false);
        }
    }

    MoveToState(State::Idle);
}

void DeviceSynchronizer::MoveToState(const State targetState)
{
    mState = targetState;
    ChipLogDetail(NotSpecified, "DeviceSynchronizer moving to [%10.10s]", GetStateStr());
}

const char * DeviceSynchronizer::GetStateStr() const
{
    switch (mState)
    {
    case State::Idle:
        return "Idle";

    case State::Connecting:
        return "Connecting";

    case State::AwaitingResponse:
        return "AwaitingResponse";

    case State::ReceivedResponse:
        return "ReceivedResponse";

    case State::ReceivedError:
        return "ReceivedError";

    case State::GettingUid:
        return "GettingUid";
    }
    return "N/A";
}

} // namespace admin
