#include "agent_audiomediaport.h"
#include "logger.h"
#include <fstream>

void AgentAudioMediaPort::onFrameRequested(pj::MediaFrame &frame)
{
    static double phase = 0.0;
    static int frameCount = 0;

    const int sampleRate = 8000;
    const int channels = 1;
    const int duration_ms = 20;
    const int samplesPerFrame = sampleRate * duration_ms / 1000;
    const int bytesPerSample = 2;
    const int frameSize = samplesPerFrame * channels * bytesPerSample;

    frame.size = frameSize;
    frame.buf.resize(frameSize);

    const int framesPerCycle = 30;
    int cyclePos = frameCount % framesPerCycle;

    double freq = 0.0;
    if (cyclePos < 10) {
        freq = 300.0;
    }
    else if (cyclePos < 20) {
        freq = 500.0;
    }
    else {
        freq = 0.0;
    }

    for (int i = 0; i < samplesPerFrame; ++i) {
        int16_t sample = 0;
        if (freq > 0.0) {
            sample = static_cast<int16_t>(std::sin(phase) * 6000); // 6000 是振幅
            phase += 2.0 * M_PI * freq / sampleRate;
            if (phase > 2.0 * M_PI)
                phase -= 2.0 * M_PI;
        }
        frame.buf[i * 2 + 0] = sample & 0xFF;
        frame.buf[i * 2 + 1] = (sample >> 8) & 0xFF;
    }

    static std::ofstream pcm_out(
        "input.pcm",
        std::ios::binary | std::ios::out | std::ios::trunc);
    if (!pcm_out.is_open()) {
        LOG_ERROR("Failed to open output.pcm");
        return;
    }
    pcm_out.write(reinterpret_cast<char *>(frame.buf.data()), frame.size);

    ++frameCount;
    LOG_INFO("Simulated frame {} with freq {}", frameCount, freq);
}

void AgentAudioMediaPort::onFrameReceived(pj::MediaFrame &frame)
{
    LOG_INFO("{} frame size: {}", __FUNCTION__, frame.size);

    static std::ofstream pcm_out(
        "output.pcm",
        std::ios::binary | std::ios::out | std::ios::trunc);
    if (!pcm_out.is_open()) {
        LOG_ERROR("Failed to open output.pcm");
        return;
    }
    pcm_out.write(reinterpret_cast<char *>(frame.buf.data()), frame.size);
}

/*
    // LOG_INFO(">>> {}", __FUNCTION__);
    // LOG_INFO(" frame type: {}", frame.type);
    // for (unsigned i = 0; i < frame.size; ++i) {
    // LOG_INFO(" frame[{}]: {}", i, static_cast<int>(frame.buf[i]));
    // }
    // LOG_INFO("<<< {}", __FUNCTION__);
*/

#include "caller.h"
#include "vaccount.h"
#include "request.hpp"
#include "caller_queue.h"
#include "logger.h"
#include "request.hpp"
#include "global.h"

voip::Caller::Caller(voip::VAccount &acc, int call_id) :
    pj::Call(acc, call_id),
    acc_(acc),
    m_aud_media_port(std::make_shared<AgentAudioMediaPort>())
{
    pj::MediaFormatAudio fmt;
    fmt.type = PJMEDIA_TYPE_AUDIO;
    fmt.id = PJMEDIA_FORMAT_PCMA; // 或 PCM16, PCMA, etc.
    fmt.clockRate = 8000;         // 8000Hz
    fmt.channelCount = 1;         //
    fmt.frameTimeUsec = 20000;    // 20ms
    fmt.bitsPerSample = 16;

    m_aud_media_port->createPort("media-port", fmt);

    // m_aud_media_port2->createPort("media-port2", fmt);
}

voip::Caller::~Caller()
{
    pj::CallOpParam prm;
    this->hangup(prm);
}

void voip::Caller::call(
    const std::string &phone,
    const std::string &client_id,
    const int dialplan_id)
{
    m_dialplan_id = dialplan_id;
    m_phone = phone;
    m_client_id = client_id;
    aud_media_recorder_.reset();
    aud_media_recorder_ = std::make_shared<pj::AudioMediaRecorder>();
    auto now = std::chrono::system_clock::now();
    now_time = std::chrono::system_clock::to_time_t(now);
    m_filename = phone + "_" +
                 std::to_string(dialplan_id) + "_" +
                 std::to_string(now_time) + ".wav";
    // aud_media_recorder_->createRecorder(m_filename);
    const std::string dst_uri = "sip:" + phone + "@" + acc_.getHost();
    LOG_INFO("dst_uri: {}", dst_uri);
    const pj::CallOpParam prm {true};
    this->makeCall(dst_uri, prm);
}

void voip::Caller::onCallTsxState(pj::OnCallTsxStateParam &prm)
{
    PJ_UNUSED_ARG(prm);

    // pj::CallInfo ci = getInfo();

    // int statusCode = ci.lastStatusCode;
    // std::string statusText = ci.lastReason;

    // LOG_INFO("call status: {} {}", statusCode, statusText);

    // if (statusCode == 404) {
    // }
    // else if (statusCode == 486) {
    // }
    // else if (statusCode == 603) {
    // }
    // else if (statusCode >= 400) {
    // }
}

void voip::Caller::onCallState(pj::OnCallStateParam &prm)
{
    PJ_UNUSED_ARG(prm);

    pj::CallInfo ci = getInfo();
    LOG_INFO("call id: {} phone: {} state: {} code:{}",
             ci.id, m_phone, ci.stateText, (int)ci.lastStatusCode);
    if (!ci.lastReason.empty()) {
        LOG_INFO("call reason: {}", ci.lastReason);
    }

    switch (ci.state) {
        case PJSIP_INV_STATE_CONNECTING: {
            LOG_INFO(">>> call: {}, phone: {} connecting", ci.id, m_phone);
            break;
        }
        case PJSIP_INV_STATE_NULL: {
            LOG_INFO(">>> call: {}, phone: {} null", ci.id, m_phone);
            break;
        }
        case PJSIP_INV_STATE_CALLING: {
            LOG_INFO(">>> call: {}, phone: {} calling", ci.id, m_phone);
            // 其他线程接收到已经接通的线程的通知后，会结束拨打
            break;
        }
        case PJSIP_INV_STATE_CONFIRMED: {
            LOG_INFO(">>> call: {}, phone: {} confirmed", ci.id, m_phone);
            // 当前线程如果已经接通了，通知其他线程挂断电话
            break;
        }
        case PJSIP_INV_STATE_DISCONNECTED: {
            LOG_INFO(">>> call: {}, phone: {} disconnected", ci.id, m_phone);
            break;
        }
        default:
            break;
    }
}

void voip::Caller::onCallMediaState(pj::OnCallMediaStateParam &prm)
{
    PJ_UNUSED_ARG(prm);

    pj::CallInfo ci = getInfo();
    LOG_INFO("call: {} Media State Changed: {}, media size: {}", ci.id, ci.stateText, ci.media.size());

    pj::AudioMedia *aud_med;
    pj::AudDevManager &mgr = pj::Endpoint::instance().audDevManager();
    auto cap_dev_med = mgr.getCaptureDevMedia();
    auto play_dev_med = mgr.getPlaybackDevMedia();

    for (unsigned i = 0; i < ci.media.size(); ++i) {
        if (ci.media[i].type == PJMEDIA_TYPE_AUDIO) {
            LOG_INFO("used media index: {}", i);
            aud_med = (pj::AudioMedia *)getMedia(i);

            // m_aud_media_player->startTransmit(*aud_med);
            // cap_dev_med.startTransmit(*aud_med);
            // aud_med->startTransmit(play_dev_med);
            aud_med->startTransmit(*m_aud_media_port);
            m_aud_media_port->startTransmit(*aud_med);
        }
    }
}

为什么客户那边（被呼叫方听到我的模拟音频）