/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 "syscfg/syscfg.h"

#include "host/ble_gap.h"
#include "host/ble_hs.h"
#include "audio/ble_audio_broadcast_source.h"
#include "services/auracast/ble_svc_auracast.h"

int
ble_svc_auracast_create(const struct ble_svc_auracast_create_params *params,
                        uint8_t *auracast_instance,
                        ble_audio_broadcast_destroy_fn *destroy_cb,
                        void *args, ble_gap_event_fn *gap_cb)
{
    struct ble_broadcast_create_params create_params;
    struct ble_gap_periodic_adv_params periodic_params = { 0 };
    struct ble_gap_ext_adv_params extended_params = {
        .scannable = 0,
        .connectable = 0,
        .primary_phy = BLE_HCI_LE_PHY_1M,
    };
    uint8_t adv_instance;
    uint8_t auracast_svc_data[251] = { 0 };
    uint8_t data_offset = 1;

    uint8_t features = 0;
    int rc;

    features |= params->big_params->encryption;

    if ((params->frame_duration == 10000) &&
        (((params->sampling_frequency == 16000) &&
          (params->bitrate == 32000)) ||
         ((params->sampling_frequency == 24000) &&
          (params->bitrate == 48000)))) {
        features |= 0x02;
    }

    if (params->sampling_frequency == 48000) {
        features |= 0x04;
    }


    auracast_svc_data[data_offset] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16;
    data_offset++;
    put_le16(&auracast_svc_data[data_offset],
             BLE_BROADCAST_PUB_ANNOUNCEMENT_SVC_UUID);
    data_offset += 2;
    auracast_svc_data[data_offset] = features;
    data_offset++;
    /** Metadata */
    if (params->program_info != NULL) {
        auracast_svc_data[data_offset] = strlen(params->program_info) + 2;
        data_offset++;
        auracast_svc_data[data_offset] = strlen(params->program_info) + 1;
        data_offset++;
        auracast_svc_data[data_offset] = 3;
        data_offset++;
        memcpy(&auracast_svc_data[data_offset], params->program_info,
               strlen(params->program_info));
        data_offset += strlen(params->program_info);
    }

    auracast_svc_data[0] = data_offset - 1;

    rc = ble_gap_adv_get_free_instance(&adv_instance);
    if (rc) {
        return BLE_HS_ENOENT;
    }

    if (params->secondary_phy == BLE_HCI_LE_PHY_2M &&
        !MYNEWT_VAL(BLE_PHY_2M)) {
        return BLE_HS_EINVAL;
    }

    extended_params.own_addr_type = params->own_addr_type;
    extended_params.sid = params->sid;
    extended_params.secondary_phy = params->secondary_phy;

    create_params.base = params->base;
    create_params.extended_params = &extended_params;
    create_params.periodic_params = &periodic_params;
    create_params.name = params->name;
    create_params.adv_instance = adv_instance;
    create_params.big_params = params->big_params;
    create_params.svc_data = auracast_svc_data;
    create_params.svc_data_len = data_offset;

    *auracast_instance = adv_instance;

    return ble_audio_broadcast_create(&create_params,
                                      destroy_cb, args, gap_cb);
}

int
ble_svc_auracast_terminate(uint8_t auracast_instance)
{
    return ble_audio_broadcast_destroy(auracast_instance);
}

int
ble_svc_auracast_start(uint8_t auracast_instance, ble_iso_event_fn *cb, void *cb_arg)
{

    return ble_audio_broadcast_start(auracast_instance, cb, cb_arg);
}

int
ble_svc_auracast_stop(uint8_t auracast_instance)
{
    return ble_audio_broadcast_stop(auracast_instance);
}
