package com.binho.cosmicsdk;

import java.util.Arrays;

public final class Types {
    public enum NotificationType {
        NOTIF_I3C_HJ(0),
        NOTIF_I3C_IBI(1),
        NOTIF_GPIO(2),
        NOTIF_UART(3),
        NOTIF_UNKNOWN(4);

        private final int value;

        NotificationType(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }

        public static NotificationType fromValue(int value) {
            for (NotificationType type : values()) {
                if (type.value == value) {
                    return type;
                }
            }
            return NOTIF_UNKNOWN;
        }
    }

    public enum I2cBus {
        I2C_BUS_A(0x00),
        I2C_BUS_B(0x01);

        private final int value;

        I2cBus(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum I2cPullUp {
        I2C_PULLUP_150Ohm(0x00),
        I2C_PULLUP_220Ohm(0x01),
        I2C_PULLUP_330Ohm(0x02),
        I2C_PULLUP_470Ohm(0x03),
        I2C_PULLUP_680Ohm(0x04),
        I2C_PULLUP_1kOhm(0x05),
        I2C_PULLUP_1_5kOhm(0x06),
        I2C_PULLUP_2_2kOhm(0x07),
        I2C_PULLUP_3_3kOhm(0x08),
        I2C_PULLUP_4kOhm(0x09),
        I2C_PULLUP_4_7kOhm(0x0A),
        I2C_PULLUP_10kOhm(0x0B),
        I2C_PULLUP_DISABLE(0x0C);

        private final int value;

        I2cPullUp(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum I3cPushPullRate {
        PUSH_PULL_2_5_MHz_DC_10(0),
        PUSH_PULL_2_5_MHz_DC_15(1),
        PUSH_PULL_2_5_MHz_DC_20(2),
        PUSH_PULL_2_5_MHz_DC_25(3),
        PUSH_PULL_3_125_MHz_DC_12_5(4),
        PUSH_PULL_3_125_MHz_DC_18_75(5),
        PUSH_PULL_3_125_MHz_DC_25(6),
        PUSH_PULL_3_125_MHz_DC_31_25(7),
        PUSH_PULL_5_MHz_DC_20(8),
        PUSH_PULL_5_MHz_DC_30(9),
        PUSH_PULL_5_MHz_DC_40(10),
        PUSH_PULL_5_MHz_DC_50(11),
        PUSH_PULL_6_25_MHz_DC_25(12),
        PUSH_PULL_6_25_MHz_DC_37_5(13),
        PUSH_PULL_6_25_MHz_DC_50(14),
        PUSH_PULL_7_5_MHz_DC_30(15),
        PUSH_PULL_7_5_MHz_DC_45(16),
        PUSH_PULL_10_MHz_DC_40(17),
        PUSH_PULL_12_5_MHz_DC_50(18);

        private final int value;

        I3cPushPullRate(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum I3cOpenDrainTransferRate {
        OPEN_DRAIN_100_KHz(0),
        OPEN_DRAIN_400_KHz(1),
        OPEN_DRAIN_1_MHz(2),
        OPEN_DRAIN_2_MHz(3),
        OPEN_DRAIN_4_17_MHz(4);

        private final int value;

        I3cOpenDrainTransferRate(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum I2cTransferRate {
        STANDARD_MODE(0),
        FAST_MODE(1),
        FAST_MODE_PLUS(2),
        HIGH_SPEED_MODE(3),
        ULTRA_FAST_MODE(4);

        private final int value;

        I2cTransferRate(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum I3cDriveStrength {
        STANDARD(0),
        FAST(1);

        private final int value;

        I3cDriveStrength(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum I3cTransferDirection {
        WRITE(0),
        READ(1);

        private final int value;

        I3cTransferDirection(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public static final class I3cTransferFlags {
        public static final int I3C_XFER_NONE = 0;
        public static final int I3C_XFER_NONSTOP = 1 << 0;
        public static final int I3C_XFER_START_WITH_7E = 1 << 1;

        private I3cTransferFlags() {
        }
    }

    public enum I3cTargetResetDefByte {
        NO_RESET(0x00),
        RESET_I3C_PERIPHERAL(0x01),
        RESET_WHOLE_TARGET(0x02),
        RESET_DEBUG_NETWORK(0x03),
        VIRTUAL_TARGET_DETECT(0x04),
        RETURN_TIME_RESET_PERIPHERAL(0x81),
        RETURN_TIME_RESET_WHOLE_TARGET(0x82),
        RETURN_TIME_DEBUG_NETWORK_RESET(0x83),
        RETURN_VIRTUAL_TARGET_INDICATION(0x84);

        private final int value;

        I3cTargetResetDefByte(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public static final class I3cEvent {
        public static final int IBI = 0x01;
        public static final int CR = 0x02;
        public static final int HJ = 0x08;

        private I3cEvent() {
        }
    }

    public enum UartBaudRate {
        UART_BAUD_600(0x00),
        UART_BAUD_1200(0x01),
        UART_BAUD_2400(0x02),
        UART_BAUD_4800(0x03),
        UART_BAUD_9600(0x04),
        UART_BAUD_14400(0x05),
        UART_BAUD_19200(0x06),
        UART_BAUD_38400(0x07),
        UART_BAUD_56000(0x08),
        UART_BAUD_57600(0x09),
        UART_BAUD_115200(0x0A);

        private final int value;

        UartBaudRate(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum UartParity {
        UART_PARITY_NONE(0x00),
        UART_PARITY_EVEN(0x01),
        UART_PARITY_ODD(0x02);

        private final int value;

        UartParity(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum UartDataSize {
        UART_DATA_SIZE_7(0x00),
        UART_DATA_SIZE_8(0x01);

        private final int value;

        UartDataSize(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum UartStopBit {
        UART_STOP_BIT_1(0x00),
        UART_STOP_BIT_2(0x01);

        private final int value;

        UartStopBit(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum UartHwHandshake {
        UART_HW_HANDSHAKE_DIS(0x00),
        UART_HW_HANDSHAKE_EN(0x01);

        private final int value;

        UartHwHandshake(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum GpioPinNumber {
        GPIO_1(0x00),
        GPIO_2(0x01),
        GPIO_3(0x02),
        GPIO_4(0x03),
        GPIO_5(0x04),
        GPIO_6(0x05);

        private final int value;

        GpioPinNumber(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum GpioLogicLevel {
        GPIO_LOW(0x00),
        GPIO_HIGH(0x01);

        private final int value;

        GpioLogicLevel(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }

        public static GpioLogicLevel fromValue(int value) {
            return value == GPIO_HIGH.value ? GPIO_HIGH : GPIO_LOW;
        }
    }

    public enum GpioFunctionality {
        GPIO_DIGITAL_INPUT(0x00),
        GPIO_DIGITAL_OUTPUT(0x01);

        private final int value;

        GpioFunctionality(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum GpioTriggerType {
        GPIO_TRIGGER_RISING_EDGE(0x01),
        GPIO_TRIGGER_FALLING_EDGE(0x02),
        GPIO_TRIGGER_BOTH_EDGES(0x03);

        private final int value;

        GpioTriggerType(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum SpiBitOrder {
        SPI_BIT_ORDER_MSB(0x00),
        SPI_BIT_ORDER_LSB(0x01);

        private final int value;

        SpiBitOrder(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum SpiMode {
        SPI_MODE_0(0x00),
        SPI_MODE_1(0x01),
        SPI_MODE_2(0x02),
        SPI_MODE_3(0x03);

        private final int value;

        SpiMode(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum SpiDataWidth {
        SPI_DATA_WIDTH_8_BITS(0x00),
        SPI_DATA_WIDTH_16_BITS(0x01);

        private final int value;

        SpiDataWidth(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum SpiChipSelect {
        SPI_CHIP_SELECT_0(0x00),
        SPI_CHIP_SELECT_1(0x01),
        SPI_CHIP_SELECT_2(0x02),
        SPI_CHIP_SELECT_3(0x03);

        private final int value;

        SpiChipSelect(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public enum SpiChipSelectPolarity {
        SPI_CS_ACTIVE_LOW(0x00),
        SPI_CS_ACTIVE_HIGH(0x01);

        private final int value;

        SpiChipSelectPolarity(int value) {
            this.value = value;
        }

        public int value() {
            return value;
        }
    }

    public record DeviceInfo(
            String manufacturer,
            String productName,
            String serialNumber,
            String fwVersion,
            String hwVersion
    ) {
    }

    public record I3cTargetConfiguration(
            int targetType,
            boolean ibiRequest,
            boolean crRequest,
            boolean daaUseSetdasa,
            boolean daaUseSetaasa,
            boolean daaUseEntdaa,
            boolean ibiTimestampEnable,
            boolean pendingReadCapability
    ) {
        public byte toByte() {
            int value = 0;
            value |= targetType & 0x01;
            value |= ibiRequest ? 1 << 1 : 0;
            value |= crRequest ? 1 << 2 : 0;
            value |= daaUseSetdasa ? 1 << 3 : 0;
            value |= daaUseSetaasa ? 1 << 4 : 0;
            value |= daaUseEntdaa ? 1 << 5 : 0;
            value |= ibiTimestampEnable ? 1 << 6 : 0;
            value |= pendingReadCapability ? 1 << 7 : 0;
            return (byte) value;
        }

        public static I3cTargetConfiguration fromByte(byte value) {
            int raw = Byte.toUnsignedInt(value);
            return new I3cTargetConfiguration(
                    raw & 0x01,
                    (raw & (1 << 1)) != 0,
                    (raw & (1 << 2)) != 0,
                    (raw & (1 << 3)) != 0,
                    (raw & (1 << 4)) != 0,
                    (raw & (1 << 5)) != 0,
                    (raw & (1 << 6)) != 0,
                    (raw & (1 << 7)) != 0
            );
        }
    }

    public record I3cBcr(
            byte raw,
            boolean maxDataSpeedLimit,
            boolean ibiRequestCapable,
            boolean ibiPayload,
            boolean offlineCapable,
            boolean virtualTargetSupport,
            boolean advancedCapabilities,
            int deviceRole
    ) {
        public static I3cBcr fromByte(byte value) {
            int raw = Byte.toUnsignedInt(value);
            return new I3cBcr(
                    value,
                    (raw & (1 << 0)) != 0,
                    (raw & (1 << 1)) != 0,
                    (raw & (1 << 2)) != 0,
                    (raw & (1 << 3)) != 0,
                    (raw & (1 << 4)) != 0,
                    (raw & (1 << 5)) != 0,
                    (raw >> 6) & 0x03
            );
        }
    }

    public record I3cTargetInfo(
            int staticAddress,
            int dynamicAddress,
            byte[] pid,
            I3cBcr bcr,
            int dcr,
            int mwl,
            int mrl,
            int maxIbiPayloadLength,
            I3cTargetConfiguration configuration
    ) {
        public I3cTargetInfo {
            pid = pid == null ? new byte[6] : Arrays.copyOf(pid, 6);
        }
    }

    public record I3cHotJoinNotification(byte[] pid, int bcr, int dcr, int dynamicAddress) {
    }

    public record I3cIbiNotification(int address, byte[] payload) {
    }

    public record GpioInterruptNotification(int pinNumber) {
    }

    public record UartRxNotification(byte[] data) {
    }

    public record Notification(
            NotificationType type,
            byte[] rawPayload,
            I3cHotJoinNotification i3cHotJoin,
            I3cIbiNotification i3cIbi,
            GpioInterruptNotification gpio,
            UartRxNotification uartRx
    ) {
    }

    public record I2cScanResult(int[] addresses7Bit, int[] addresses10Bit) {
    }

    public record I3cGetMrlResult(int maxReadLength, Integer ibiLength) {
    }

    private Types() {
    }
}
