/*
 *   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.
 *
 */

#include "SetupPayloadGenerateCommand.h"
#include <lib/core/CHIPTLV.h>
#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <setup_payload/ManualSetupPayloadParser.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <setup_payload/QRCodeSetupPayloadParser.h>
#include <setup_payload/SetupPayload.h>

using namespace ::chip;

void SetupPayloadGenerateCommand::ConfigurePayload(SetupPayload & payload)
{
    if (mDiscriminator.HasValue())
    {
        payload.discriminator.SetLongValue(mDiscriminator.Value());
    }

    if (mSetUpPINCode.HasValue())
    {
        payload.setUpPINCode = mSetUpPINCode.Value();
    }

    if (mVersion.HasValue())
    {
        payload.version = mVersion.Value();
    }

    if (mVendorId.HasValue())
    {
        payload.vendorID = mVendorId.Value();
    }

    if (mProductId.HasValue())
    {
        payload.productID = mProductId.Value();
    }

    if (mCommissioningMode.HasValue())
    {
        payload.commissioningFlow = static_cast<CommissioningFlow>(mCommissioningMode.Value());
    }
}

CHIP_ERROR SetupPayloadGenerateQRCodeCommand::Run()
{
    SetupPayload payload;

    if (mExistingPayload.HasValue())
    {
        CHIP_ERROR err = QRCodeSetupPayloadParser(mExistingPayload.Value()).populatePayload(payload);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(chipTool, "Invalid existing payload: %" CHIP_ERROR_FORMAT, err.Format());
            return err;
        }
    }

    ConfigurePayload(payload);

    if (mRendezvous.HasValue())
    {
        payload.rendezvousInformation.Emplace().SetRaw(mRendezvous.Value());
    }
    else if (!payload.rendezvousInformation.HasValue())
    {
        // Default to not having anything in the discovery capabilities.
        payload.rendezvousInformation.SetValue(RendezvousInformationFlag::kNone);
    }

    if (mTLVBytes.HasValue())
    {
        CHIP_ERROR err = PopulatePayloadTLVFromBytes(payload, mTLVBytes.Value());
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(chipTool, "Unable to populate payload TLV: %" CHIP_ERROR_FORMAT, err.Format());
            return err;
        }
    }

    QRCodeSetupPayloadGenerator generator(payload);
    generator.SetAllowInvalidPayload(mAllowInvalidPayload.ValueOr(false));

    std::string code;
    ReturnErrorOnFailure(generator.payloadBase38RepresentationWithAutoTLVBuffer(code));
    // CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE includes various prefixes we don't
    // control (timestamps, process ids, etc).  Let's assume (hope?) that
    // those prefixes use up no more than half the total available space.
    constexpr size_t chunkSize = CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE / 2;
    while (code.size() > chunkSize)
    {
        ChipLogProgress(chipTool, "QR Code: %s", code.substr(0, chunkSize).c_str());
        code = code.substr(chunkSize);
    }
    ChipLogProgress(chipTool, "QR Code: %s", code.c_str());

    return CHIP_NO_ERROR;
}

CHIP_ERROR SetupPayloadGenerateQRCodeCommand::PopulatePayloadTLVFromBytes(SetupPayload & payload, const ByteSpan & tlvBytes)
{
    // First clear out all the existing TVL bits from the payload.  Ignore
    // errors here, because we don't care if those bits are not present.
    payload.removeSerialNumber();

    auto existingVendorData = payload.getAllOptionalVendorData();
    for (auto & data : existingVendorData)
    {
        payload.removeOptionalVendorData(data.tag);
    }

    if (tlvBytes.empty())
    {
        // Used to just clear out the existing TLV.
        return CHIP_NO_ERROR;
    }

    TLV::TLVReader reader;
    reader.Init(tlvBytes);

    // Data is a TLV structure.
    ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));

    TLV::TLVType outerType;
    ReturnErrorOnFailure(reader.EnterContainer(outerType));

    CHIP_ERROR err;
    while ((err = reader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = reader.GetTag();
        if (!TLV::IsContextTag(tag))
        {
            ChipLogError(chipTool, "Unexpected non-context TLV tag.");
            return CHIP_ERROR_INVALID_TLV_TAG;
        }

        uint8_t tagNum = static_cast<uint8_t>(TLV::TagNumFromTag(tag));
        if (tagNum < 0x80)
        {
            // Matter-common tag.
            if (tagNum != kSerialNumberTag)
            {
                ChipLogError(chipTool, "No support yet for Matter-common tags other than serial number");
                return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
            }

            // Serial number can be a string or an unsigned integer.
            if (reader.GetType() == TLV::kTLVType_UTF8String)
            {
                CharSpan data;
                ReturnErrorOnFailure(reader.Get(data));
                ReturnErrorOnFailure(payload.addSerialNumber(std::string(data.data(), data.size())));
                continue;
            }

            if (reader.GetType() == TLV::kTLVType_UnsignedInteger)
            {
                uint32_t value;
                ReturnErrorOnFailure(reader.Get(value));
                ReturnErrorOnFailure(payload.addSerialNumber(value));
                continue;
            }

            ChipLogError(chipTool, "Unexpected type for serial number: %d", to_underlying(reader.GetType()));
            return CHIP_ERROR_WRONG_TLV_TYPE;
        }

        // Vendor tag.  We support strings and signed integers.
        if (reader.GetType() == TLV::kTLVType_UTF8String)
        {
            CharSpan data;
            ReturnErrorOnFailure(reader.Get(data));
            ReturnErrorOnFailure(payload.addOptionalVendorData(tagNum, std::string(data.data(), data.size())));
            continue;
        }

        if (reader.GetType() == TLV::kTLVType_SignedInteger)
        {
            int32_t value;
            ReturnErrorOnFailure(reader.Get(value));
            ReturnErrorOnFailure(payload.addOptionalVendorData(tagNum, value));
            continue;
        }

        ChipLogError(chipTool, "Unexpected type for vendor data: %d", to_underlying(reader.GetType()));
        return CHIP_ERROR_WRONG_TLV_TYPE;
    }

    VerifyOrReturnError(err == CHIP_END_OF_TLV, err);

    ReturnErrorOnFailure(reader.ExitContainer(outerType));
    ReturnErrorOnFailure(reader.VerifyEndOfContainer());

    return CHIP_NO_ERROR;
}

CHIP_ERROR SetupPayloadGenerateManualCodeCommand::Run()
{
    SetupPayload payload;

    if (mExistingPayload.HasValue())
    {
        CHIP_ERROR err = ManualSetupPayloadParser(mExistingPayload.Value()).populatePayload(payload);
        if (err != CHIP_NO_ERROR)
        {
            ChipLogError(chipTool, "Invalid existing payload: %" CHIP_ERROR_FORMAT, err.Format());
            return err;
        }
    }

    ConfigurePayload(payload);

    ManualSetupPayloadGenerator generator(payload);
    generator.SetAllowInvalidPayload(mAllowInvalidPayload.ValueOr(false));
    generator.SetForceShortCode(mForceShortCode.ValueOr(false));

    std::string code;
    ReturnErrorOnFailure(generator.payloadDecimalStringRepresentation(code));
    ChipLogProgress(chipTool, "Manual Code: %s", code.c_str());

    return CHIP_NO_ERROR;
}
