/*
 *
 *    Copyright (c) 2022 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.
 */

/**
 *    @file
 *      Implementation of the native methods expected by the Python
 *      version of Chip Device Manager.
 *
 */

#include <string>

#include <controller/CHIPDeviceController.h>
#include <controller/python/matter/native/PyChipError.h>
#include <json/json.h>
#include <lib/core/CHIPError.h>
#include <lib/core/TLV.h>
#include <lib/dnssd/Resolver.h>
#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <setup_payload/SetupPayload.h>

using namespace chip;

typedef void (*IterateDiscoveredCommissionableNodesFunct)(const char * deviceInfoJson, size_t deviceInfoLen);

extern "C" {

bool pychip_DeviceController_HasDiscoveredCommissionableNode(Controller::DeviceCommissioner * devCtrl)
{
    for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
    {
        const Dnssd::CommissionNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
        if (dnsSdInfo == nullptr)
        {
            continue;
        }
        return true;
    }
    return false;
}

PyChipError pychip_DeviceController_DiscoverCommissionableNodes(Controller::DeviceCommissioner * devCtrl, const uint8_t filterType,
                                                                const char * filterParam)
{
    Dnssd::DiscoveryFilter filter(static_cast<Dnssd::DiscoveryFilterType>(filterType));
    switch (static_cast<Dnssd::DiscoveryFilterType>(filterType))
    {
    case Dnssd::DiscoveryFilterType::kNone:
        break;
    case Dnssd::DiscoveryFilterType::kShortDiscriminator:
    case Dnssd::DiscoveryFilterType::kLongDiscriminator:
    case Dnssd::DiscoveryFilterType::kCompressedFabricId:
    case Dnssd::DiscoveryFilterType::kVendorId:
    case Dnssd::DiscoveryFilterType::kDeviceType: {
        // For any numerical filter, convert the string to a filter value
        errno                               = 0;
        unsigned long long int numericalArg = strtoull(filterParam, nullptr, 0);
        if ((numericalArg == ULLONG_MAX) && (errno == ERANGE))
        {
            return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT);
        }
        filter.code = static_cast<uint64_t>(numericalArg);
        break;
    }
    case Dnssd::DiscoveryFilterType::kCommissioningMode:
        break;
    case Dnssd::DiscoveryFilterType::kCommissioner:
        filter.code = 1;
        break;
    case Dnssd::DiscoveryFilterType::kInstanceName:
        filter.code         = 0;
        filter.instanceName = filterParam;
        break;
    default:
        return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT);
    }

    return ToPyChipError(devCtrl->DiscoverCommissionableNodes(filter));
}

PyChipError pychip_DeviceController_StopCommissionableDiscovery(Controller::DeviceCommissioner * devCtrl)
{
    return ToPyChipError(devCtrl->StopCommissionableDiscovery());
}

void pychip_DeviceController_IterateDiscoveredCommissionableNodes(Controller::DeviceCommissioner * devCtrl,
                                                                  IterateDiscoveredCommissionableNodesFunct cb)
{
    VerifyOrReturn(cb != nullptr);

    for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
    {
        const Dnssd::CommissionNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
        if (dnsSdInfo == nullptr)
        {
            continue;
        }

        Json::Value jsonVal;

        char rotatingId[Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
        Encoding::BytesToUppercaseHexString(dnsSdInfo->rotatingId, dnsSdInfo->rotatingIdLen, rotatingId, sizeof(rotatingId));

        ChipLogProgress(Discovery, "Commissionable Node %d", i);
        jsonVal["instanceName"]       = dnsSdInfo->instanceName;
        jsonVal["hostName"]           = dnsSdInfo->hostName;
        jsonVal["port"]               = dnsSdInfo->port;
        jsonVal["longDiscriminator"]  = dnsSdInfo->longDiscriminator;
        jsonVal["vendorId"]           = dnsSdInfo->vendorId;
        jsonVal["productId"]          = dnsSdInfo->productId;
        jsonVal["commissioningMode"]  = dnsSdInfo->commissioningMode;
        jsonVal["deviceType"]         = dnsSdInfo->deviceType;
        jsonVal["deviceName"]         = dnsSdInfo->deviceName;
        jsonVal["pairingInstruction"] = dnsSdInfo->pairingInstruction;
        jsonVal["pairingHint"]        = dnsSdInfo->pairingHint;

        auto idleInterval = dnsSdInfo->GetMrpRetryIntervalIdle();
        if (idleInterval.has_value())
        {
            jsonVal["mrpRetryIntervalIdle"] = idleInterval->count();
        }

        auto activeInterval = dnsSdInfo->GetMrpRetryIntervalActive();
        if (activeInterval.has_value())
        {
            jsonVal["mrpRetryIntervalActive"] = activeInterval->count();
        }

        auto activeThreshold = dnsSdInfo->GetMrpRetryActiveThreshold();
        if (activeThreshold.has_value())
        {
            jsonVal["mrpRetryActiveThreshold"] = activeThreshold->count();
        }

        jsonVal["supportsTcpClient"] = dnsSdInfo->supportsTcpClient;
        jsonVal["supportsTcpServer"] = dnsSdInfo->supportsTcpServer;
        {
            Json::Value addresses;
            for (unsigned j = 0; j < dnsSdInfo->numIPs; ++j)
            {
                char buf[Inet::IPAddress::kMaxStringLength];
                dnsSdInfo->ipAddress[j].ToString(buf);
                addresses[j] = buf;
            }
            jsonVal["addresses"] = addresses;
        }
        if (dnsSdInfo->isICDOperatingAsLIT.has_value())
        {
            jsonVal["isICDOperatingAsLIT"] = *(dnsSdInfo->isICDOperatingAsLIT);
        }
        if (dnsSdInfo->rotatingIdLen > 0)
        {
            jsonVal["rotatingId"] = rotatingId;
        }

        {
            auto str = jsonVal.toStyledString();
            cb(str.c_str(), str.size());
        }
    }
}

bool pychip_DeviceController_GetIPForDiscoveredDevice(Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr,
                                                      uint32_t len)
{
    const Dnssd::CommissionNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(idx);
    if (dnsSdInfo == nullptr)
    {
        return false;
    }
    // TODO(cecille): Select which one we actually want.
    if (dnsSdInfo->ipAddress[0].ToString(addrStr, len) == addrStr)
    {
        return true;
    }
    return false;
}

PyChipError pychip_CreateManualCode(uint16_t longDiscriminator, uint32_t passcode, char * manualCodeBuffer, size_t inBufSize,
                                    size_t * outBufSize)
{
    SetupPayload payload;
    SetupDiscriminator discriminator;
    discriminator.SetLongValue(longDiscriminator);
    payload.discriminator = discriminator;
    payload.setUpPINCode  = passcode;
    std::string setupManualCode;

    *outBufSize    = 0;
    CHIP_ERROR err = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(setupManualCode);
    if (err == CHIP_NO_ERROR)
    {
        MutableCharSpan span(manualCodeBuffer, inBufSize);
        // Plus 1 so we copy the null terminator
        CopyCharSpanToMutableCharSpan(CharSpan(setupManualCode.c_str(), setupManualCode.length() + 1), span);
        *outBufSize = span.size();
        if (*outBufSize == 0)
        {
            err = CHIP_ERROR_NO_MEMORY;
        }
    }

    return ToPyChipError(err);
}
}
