#include "mc/can_driver.h"
#include <cstring>
#include <stdexcept>
#include <iostream>
#include <thread>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "mc/controlcan.h"

DWORD deviceType = VCI_USBCAN2; // 或 VCI_USBCAN_2E_U 等
DWORD deviceIndex = 0;          // 通常为 0（第一个设备）
DWORD channelIndex = 0;         // 通道号：0 表示 CAN1，1 表示 CAN2

CANDriver::CANDriver() = default;

CANDriver::~CANDriver()
{
    close();
}

bool CANDriver::open(const std::string &interface)
{
    if (running)
        return false;

    // 参数可解析 interface 设定 channelIndex，例如 interface="can0" => channelIndex=0
    deviceType = VCI_USBCAN2;
    deviceIndex = 0;
    channelIndex = (interface == "can1") ? 1 : 0;

    if (VCI_OpenDevice(deviceType, deviceIndex, 0) != STATUS_OK)
    {
        std::cerr << "VCI_OpenDevice failed" << std::endl;
        return false;
    }

    VCI_INIT_CONFIG config{};
    config.AccCode = 0;
    config.AccMask = 0xFFFFFFFF;
    config.Filter = 0;     // 接收所有
    config.Timing0 = 0x00; // 500Kbps 示例（需查文档确认 Timing）
    config.Timing1 = 0x1C;
    config.Mode = 0; // 正常模式

    if (VCI_InitCAN(deviceType, deviceIndex, channelIndex, &config) != STATUS_OK)
    {
        std::cerr << "VCI_InitCAN failed" << std::endl;
        VCI_CloseDevice(deviceType, deviceIndex);
        return false;
    }

    if (VCI_StartCAN(deviceType, deviceIndex, channelIndex) != STATUS_OK)
    {
        std::cerr << "VCI_StartCAN failed" << std::endl;
        VCI_CloseDevice(deviceType, deviceIndex);
        return false;
    }

    running = true;
    receiveThread = std::thread(&CANDriver::receiveThreadFunc, this);
    return true;
}

void CANDriver::close()
{
    if (!running)
        return;

    running = false;
    if (receiveThread.joinable())
        receiveThread.join();

    VCI_ResetCAN(deviceType, deviceIndex, channelIndex);
    VCI_CloseDevice(deviceType, deviceIndex);
}

bool CANDriver::sendFrame(const CANFrame &frame)
{
    if (!running)
        return false;

    VCI_CAN_OBJ obj{};
    obj.ID = frame.id;
    obj.RemoteFlag = frame.rtr ? 1 : 0;
    obj.ExternFlag = frame.ext ? 1 : 0;
    obj.SendType = 0; // 普通发送
    obj.DataLen = frame.dlc;
    std::memcpy(obj.Data, frame.data, frame.dlc);

    if (VCI_Transmit(deviceType, deviceIndex, channelIndex, &obj, 1) != 1)
    {
        std::cerr << "VCI_Transmit failed" << std::endl;
        return false;
    }

    return true;
}

void CANDriver::setReceiveCallback(ReceiveCallback callback, void *userData)
{
    this->callback = callback;
    this->userData = userData;
}

bool CANDriver::setFilter(const std::vector<can_filter> &filters)
{
    if (!running)
        return false;

    filters_ = filters;
    return applyFilters();
}

bool CANDriver::addFilter(const can_filter &filter)
{
    filters_.push_back(filter);
    return applyFilters();
}

bool CANDriver::addFilters(const std::vector<can_filter> &filters)
{
    filters_.insert(filters_.end(), filters.begin(), filters.end());
    return applyFilters();
}

bool CANDriver::applyFilters()
{
    if (!running)
        return false;

    if (filters_.empty())
    {
        setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, nullptr, 0);
        return true;
    }

    if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER,
                   filters_.data(), filters_.size() * sizeof(can_filter)) < 0)
    {
        perror("setsockopt");
        return false;
    }

    return true;
}

void CANDriver::receiveThreadFunc()
{
    while (running)
    {
        VCI_CAN_OBJ rec[100];
        ULONG len = VCI_Receive(deviceType, deviceIndex, channelIndex, rec, 100, 10);
        if (len == 0)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            continue;
        }

        for (ULONG i = 0; i < len && callback; ++i)
        {
            CANFrame frame;
            frame.id = rec[i].ID;
            frame.ext = rec[i].ExternFlag != 0;
            frame.rtr = rec[i].RemoteFlag != 0;
            frame.dlc = rec[i].DataLen;
            std::memcpy(frame.data, rec[i].Data, frame.dlc);
            callback(frame, userData);
        }
    }
}
