using CosmicDriver;

using var sdk = new CosmicSdk(2000);
if (!sdk.Connect()) throw new Exception("Failed to connect to a Binho device.");

var (deviceInfoStatus, info) = sdk.GetDeviceInfo();
AssertStatus(deviceInfoStatus, "GetDeviceInfo");
PrintDeviceInfo(info!);

Console.WriteLine("Setting I3C VTARG to 3.3V...");
AssertStatus(sdk.I3cSetBusVoltage(3300), "I3cSetBusVoltage");

Console.WriteLine("Initializing I3C controller...");
AssertStatus(
    sdk.I3cControllerInit(
        I3cPushPullRate.PUSH_PULL_3_125_MHz_DC_31_25,
        I3cOpenDrainTransferRate.OPEN_DRAIN_1_MHz,
        I2cTransferRate.FAST_MODE,
        I3cDriveStrength.STANDARD),
    "I3cControllerInit",
    ResultCode.SUCCESS,
    ResultCode.FW_INTERFACE_ALREADY_INITIALIZED);

Console.WriteLine("Initializing I3C bus...");
AssertStatus(sdk.I3cInitBus(), "I3cInitBus");

Console.WriteLine("Issuing HDR-DDR write...");
AssertStatus(sdk.I3cHdrDdrWrite(0x08, 0x04, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), "I3cHdrDdrWrite");

Console.WriteLine("Resetting target internal register pointer with SDR write...");
AssertStatus(sdk.I3cSdrWrite(0x08, [0x00], [], I3cTransferFlags.I3C_XFER_START_WITH_7E), "I3cSdrWrite(pointer reset)");

Console.WriteLine("Issuing HDR-DDR read...");
var (hdrReadStatus, hdrReadPayload) = sdk.I3cHdrDdrRead(0x08, 0x80, 10);
AssertStatus(hdrReadStatus, "I3cHdrDdrRead");
if (hdrReadPayload is null) throw new Exception("I3cHdrDdrRead returned empty payload.");
Console.WriteLine($"HDR-DDR read payload: {string.Join(" ", hdrReadPayload.Select(b => $"0x{b:X2}"))}");

static void PrintDeviceInfo(DeviceInfo info)
{
    Console.WriteLine($"Manufacturer: {info.Manufacturer}");
    Console.WriteLine($"Product name: {info.ProductName}");
    Console.WriteLine($"Serial number: {info.SerialNumber}");
    Console.WriteLine($"FW version: {info.FwVersion}");
    Console.WriteLine($"HW version: {info.HwVersion}");
}

static void AssertStatus(ResultCode status, string operation, params ResultCode[] expected)
{
    if (expected.Length == 0) expected = [ResultCode.SUCCESS];
    if (!expected.Contains(status))
    {
        throw new Exception($"{operation} failed. STATUS=0x{(ushort)status:X4}. Expected: {string.Join(", ", expected.Select(e => $"0x{(ushort)e:X4}"))}");
    }
}
