/*
 *
 *    Copyright (c) 2020 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 "commands/clusters/SubscriptionsCommands.h"
#include "commands/common/Commands.h"
#include "commands/example/ExampleCredentialIssuerCommands.h"
#include <zap-generated/cluster/Commands.h>

#include "CastingServer.h"
#include "CastingUtils.h"
#if defined(ENABLE_CHIP_SHELL)
#include "CastingShellCommands.h"
#include <lib/shell/Engine.h> // nogncheck
#include <thread>
#endif

#include "LinuxCommissionableDataProvider.h"
#include "Options.h"
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include <platform/TestOnlyCommissionableDataProvider.h>

using namespace chip;
using chip::ArgParser::HelpOptions;
using chip::ArgParser::OptionDef;
using chip::ArgParser::OptionSet;

#if defined(ENABLE_CHIP_SHELL)
using chip::Shell::Engine;
#endif

CHIP_ERROR InitCommissionableDataProvider(LinuxCommissionableDataProvider & provider, LinuxDeviceOptions & options)
{
    chip::Optional<uint32_t> setupPasscode;

    if (options.payload.setUpPINCode != 0)
    {
        setupPasscode.SetValue(options.payload.setUpPINCode);
    }
    else if (!options.spake2pVerifier.HasValue())
    {
        uint32_t defaultTestPasscode = 0;
        chip::DeviceLayer::TestOnlyCommissionableDataProvider TestOnlyCommissionableDataProvider;
        VerifyOrDie(TestOnlyCommissionableDataProvider.GetSetupPasscode(defaultTestPasscode) == CHIP_NO_ERROR);

        ChipLogError(Support,
                     "*** WARNING: Using temporary passcode %u due to no neither --passcode or --spake2p-verifier-base64 "
                     "given on command line. This is temporary and will disappear. Please update your scripts "
                     "to explicitly configure onboarding credentials. ***",
                     static_cast<unsigned>(defaultTestPasscode));
        setupPasscode.SetValue(defaultTestPasscode);
        options.payload.setUpPINCode = defaultTestPasscode;
    }
    else
    {
        // Passcode is 0, so will be ignored, and verifier will take over. Onboarding payload
        // printed for debug will be invalid, but if the onboarding payload had been given
        // properly to the commissioner later, PASE will succeed.
    }

    // Default to minimum PBKDF iterations
    uint32_t spake2pIterationCount = chip::Crypto::kSpake2p_Min_PBKDF_Iterations;
    if (options.spake2pIterations != 0)
    {
        spake2pIterationCount = options.spake2pIterations;
    }
    ChipLogError(Support, "PASE PBKDF iterations set to %u", static_cast<unsigned>(spake2pIterationCount));

    return provider.Init(options.spake2pVerifier, options.spake2pSalt, spake2pIterationCount, setupPasscode,
                         options.payload.discriminator.GetLongValue());
}

// To hold SPAKE2+ verifier, discriminator, passcode
LinuxCommissionableDataProvider gCommissionableDataProvider;

// For shell and command line processing of commands
ExampleCredentialIssuerCommands gCredIssuerCommands;
Commands gCommands;

CHIP_ERROR ProcessClusterCommand(int argc, char ** argv)
{
    if (!CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->IsInitialized())
    {
        CastingServer::GetInstance()->SetDefaultFabricIndex(OnConnectionSuccess, OnConnectionFailure, OnNewOrUpdatedEndpoint);
    }
    gCommands.Run(argc, argv);
    return CHIP_NO_ERROR;
}

int main(int argc, char * argv[])
{
    VerifyOrDie(CHIP_NO_ERROR == chip::Platform::MemoryInit());
    VerifyOrDie(CHIP_NO_ERROR == chip::DeviceLayer::PlatformMgr().InitChipStack());

#if defined(ENABLE_CHIP_SHELL)
    Engine::Root().Init();
    std::thread shellThread([]() { Engine::Root().RunMainLoop(); });
    Shell::RegisterCastingCommands();
#endif
    CHIP_ERROR err = CHIP_NO_ERROR;

    DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(CHIP_CONFIG_KVS_PATH);

    // Init the commissionable data provider based on command line options
    // to handle custom verifiers, discriminators, etc.
    err = InitCommissionableDataProvider(gCommissionableDataProvider, LinuxDeviceOptions::GetInstance());
    SuccessOrExit(err);
    DeviceLayer::SetCommissionableDataProvider(&gCommissionableDataProvider);

    // Initialize device attestation config
    SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider());

    // Initialize device attestation verifier from a constant version
    {
        // TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
        const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore();
        SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
    }

    SuccessOrExit(err = CastingServer::GetInstance()->PreInit());

    // Enter commissioning mode, open commissioning window
    static chip::CommonCaseDeviceServerInitParams initParams;
    VerifyOrDie(CHIP_NO_ERROR == initParams.InitializeStaticResourcesBeforeServerInit());
    VerifyOrDie(CHIP_NO_ERROR == chip::Server::GetInstance().Init(initParams));

    if (argc > 1)
    {
        ChipLogProgress(AppServer, "Command line parameters detected. Skipping auto-start.");
    }
    else if (ConnectToCachedVideoPlayer() == CHIP_NO_ERROR)
    {
        ChipLogProgress(AppServer, "Skipping commissioner discovery / User directed commissioning flow.");
    }
    else
    {
        // Send discover commissioners request
        SuccessOrExit(err = CastingServer::GetInstance()->DiscoverCommissioners());

        // Give commissioners some time to respond and then ScheduleWork to initiate commissioning
        DeviceLayer::SystemLayer().StartTimer(
            chip::System::Clock::Milliseconds32(kCommissionerDiscoveryTimeoutInMs),
            [](System::Layer *, void *) { chip::DeviceLayer::PlatformMgr().ScheduleWork(InitCommissioningFlow); }, nullptr);
    }

    registerClusters(gCommands, &gCredIssuerCommands);
    registerCommandsSubscriptions(gCommands, &gCredIssuerCommands);

    if (argc > 1)
    {
        // if there are command-line arguments, then automatically start server
        ProcessClusterCommand(argc, argv);
    }

    DeviceLayer::PlatformMgr().RunEventLoop();
exit:
#if defined(ENABLE_CHIP_SHELL)
    shellThread.join();
#endif
    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(AppServer, "Failed to run TV Casting App: %s", ErrorStr(err));
        // End the program with non zero error code to indicate an error.
        return 1;
    }
    return 0;
}
