//
// Created by bruno on 3/30/25.
//

#include "messages.h"
#include "ui/ui.h"
#include "driver/uart.h"
#include "driver/systick.h"

#define T9Count 9

const char T9Table[10][T9Count] = {
        {'#', '(', ')', ';', ':', '<', '>', '/',  '0'},
        {',', '.', '?', '&', '!', ' ', '-', '_',  '1'},
        {'a', 'b', 'c', 'A', 'B', 'C', '[', ']',  '2'},
        {'d', 'e', 'f', 'D', 'E', 'F', '@', '%',  '3'},
        {'g', 'h', 'i', 'G', 'H', 'I', '~', '$',  '4'},
        {'j', 'k', 'l', 'J', 'K', 'L', '|', '*',  '5'},
        {'m', 'n', 'o', 'M', 'N', 'O', '{', '}',  '6'},
        {'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S',  '7'},
        {'t', 'u', 'v', 'T', 'U', 'V', '"', '\'', '8'},
        {'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z',  '9'}
};


uint8_t gActiveMessage = 0;
uint8_t gActiveMessageBank = 0;

StoredPacket loadedPacket;

uint8_t gKeyTimeout = 0;

void MESSAGES_SAVE() {
    uint8_t Data[8];
    EEPROM_ReadBuffer(SEQParameterEEPROM, Data, 8);
    uint8_t msgIndex = Data[1];
    if (msgIndex >= MESSAGES_COUNT) {
        msgIndex = 0;
    }
    msgIndex++;
    Data[1] = msgIndex;
    EEPROM_WriteBuffer(SEQParameterEEPROM, Data);
    EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 0,
                       (uint8_t *) &inBoundPacket + 4);   // metadata
    EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 8,
                       (uint8_t *) &inBoundPacket + 12);   // message part 1
    EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 16,
                       (uint8_t *) &inBoundPacket + 20); // message part 2
    EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 24,
                       (uint8_t *) &inBoundPacket + 28); // message part 3
    EEPROM_WriteBuffer(MESSAGES_START + (msgIndex * sizeof(StoredPacket)) + 32,
                       (uint8_t *) &inBoundPacket + 36); // message part 4

}

void MESSAGES_GET() {
    if (gActiveMessage == MESSAGES_COUNT) {
        memcpy(&loadedPacket, (uint8_t *) &dataPacket + (sizeof(DataPacket) - sizeof(StoredPacket)),
               sizeof(StoredPacket));
    } else {
        EEPROM_ReadBuffer(MESSAGES_START + (gActiveMessage * sizeof(StoredPacket)), &loadedPacket,
                          sizeof(StoredPacket));
    }
}

void MESSAGES_DELETE() {

}

void updatePrevChar(KEY_Code_t Key) {
    if (Key != prevKey) {
        prevKey = Key;
    }

}

void MESSAGES_TimeSlice500ms(void) {
    if (gKeyTimeout && gKeyTimeout++ > 2) {
        gKeyTimeout = 0;
        prevKey = KEY_EXIT;
    }
}

void MESSAGES_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) {
    gKeyTimeout = 1;
    if (gEnteringSMS != SMS_NOT_ENTERING && Key <= KEY_9) {
        if (!bKeyHeld) {
            if (!dataPTR || dataPTR < dataPacket.data) {
                dataPTR = dataPacket.data;
            }
        }
        if (gEnteringSMS == SMS_ENTERING_MESSAGE) {
            if (bKeyPressed) {
                if (prevKey != Key) {
                    dataPTR++;
                    //if (dataPTR - dataPacket.data >= DataPacketDataSize) {
                    if (dataPTR - dataPacket.data >= 19) {
                        dataPTR = dataPacket.data;
                    }
                    prevLetter = 0;
                }
                *(dataPTR - 1) = T9Table[Key][prevLetter];
                if (!bKeyHeld) {
                    prevLetter++;
                } else {
                    prevLetter--;
                }
                prevLetter = (prevLetter) % T9Count;
                updatePrevChar(Key);
            }
            return;
        } else if (gEnteringSMS == SMS_ENTERING_DEST) {
            if (!bKeyHeld) {
                if (bKeyPressed) {
                    dataPacket.dest *= 10;
                    dataPacket.dest += Key;
                    prevLetter = 0;
                }
                return;
            }
        }
    }


    switch (Key) {
        case KEY_PTT:
        case KEY_MENU:
            if (gEnteringSMS == SMS_NOT_ENTERING) {
                if (bKeyPressed) {
                    gEnteringSMS = SMS_ENTERING_DEST;
                    updatePrevChar(Key);
                }
            } else if (gEnteringSMS == SMS_ENTERING_DEST) {
                if (bKeyPressed) {
                    memset(dataPacket.data, 0, DataPacketDataSize);
                    prepareDataPacket();
                    dataPacket.flags = 0x80 | (gCurrentVfo->OUTPUT_POWER & 0x07);
                    if (dataPacket.src == 665 || dataPacket.src == 664) {

                        uint8_t out[5];
                        if (dataPacket.src == 665) {
                            const uint32_t id24 = 0xFFFFFF & (dataPacket.dest >> 4);
                            const uint8_t btn = 0x0F & (dataPacket.dest);
                            // mask just in case
//        uint32_t id24 = 0x00A38C;
//        uint8_t btn = 0x04;

                            // 3-byte big-endian ID
                            out[0] = (id24 >> 16) & 0xFF;
                            out[1] = (id24 >> 8) & 0xFF;
                            out[2] = (id24 >> 0) & 0xFF;

                            // first nibble redundancy copy: 0xBB if btn=0xB
                            out[3] = (btn << 4) | 0x04;

                            // second copy with MSB flipped (btn ^ 0x8) in the high nibble
                            out[4] = ((btn ^ 0x8) << 4);
                        } else {
                            out[0] = (dataPacket.dest >> 8) & 0xFF;
                            out[1] = dataPacket.dest & 0xFF;
                        }

                        BK4819_EnterTxMute();
                        RADIO_SetTxParameters();

                        uint16_t datX = BK4819_REG_30_ENABLE_VCO_CALIB |
                                        BK4819_REG_30_ENABLE_UNKNOWN |
                                        BK4819_REG_30_DISABLE_RX_LINK |
                                        BK4819_REG_30_DISABLE_AF_DAC |
                                        BK4819_REG_30_ENABLE_DISC_MODE |
                                        BK4819_REG_30_ENABLE_PLL_VCO |
                                        BK4819_REG_30_ENABLE_PA_GAIN |
                                        BK4819_REG_30_DISABLE_MIC_ADC |
                                        BK4819_REG_30_ENABLE_TX_DSP |
                                        BK4819_REG_30_DISABLE_RX_DSP;
                        BK4819_WriteRegister(BK4819_REG_30,
                                             datX);
                        BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
                        SYSTEM_DelayMs(20);

                        for (unsigned int x = 0; x < 15; x++) {
                            for (unsigned int y = 0; y < (dataPacket.src == 665 ? 5 : 2); y++) {
                                for (unsigned char i = 7; i < 8; i--) {
                                    if ((out[y] >> i) & 1) {
//                            datX |= BK4819_REG_30_ENABLE_PA_GAIN;
                                        BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, true);
                                        SYSTICK_DelayUs(400 * (dataPacket.src == 665 ? 3 : 2) - 325);
                                        BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
//                            datX &= ~BK4819_REG_30_ENABLE_PA_GAIN;
                                        SYSTICK_DelayUs(400 * 1 - 325);
                                    } else {
                                        BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, true);
//                            datX |= BK4819_REG_30_ENABLE_PA_GAIN;
                                        SYSTICK_DelayUs(400 * 1 - 325);
                                        BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
//                            datX &= ~BK4819_REG_30_ENABLE_PA_GAIN;
                                        SYSTICK_DelayUs(400 * (dataPacket.src == 665 ? 3 : 2) - 325);
                                    }
                                }
                            }
                            BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
                            SYSTEM_DelayMs((dataPacket.src == 665 ? 3 : 15));
                        }
                        BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
                        SYSTEM_DelayMs(100);
                        BK4819_WriteRegister(BK4819_REG_30, 0xC1FE);
                        gEnteringSMS = SMS_NOT_ENTERING;
                    } else {
                        gEnteringSMS = SMS_ENTERING_MESSAGE;
                    }
                }
                return;
            } else if (gEnteringSMS == SMS_ENTERING_MESSAGE) {
                if (bKeyPressed) {
                    if (strlen((char *) dataPacket.data)) {
                        MSG_FSKSendData(&dataPacket);
                        gEnteringSMS = SMS_NOT_ENTERING;
                    }
                }
                return;
            }
            break;
        case KEY_UP:
            if (gEnteringSMS != SMS_NOT_ENTERING) {
                if (bKeyPressed) {
                    gActiveMessageBank++;
                    gActiveMessage = gActiveMessageBank * 3;
                    if (gActiveMessage > MESSAGES_COUNT) {
                        gActiveMessage = 0;
                    }
                    if (gActiveMessageBank >= MESSAGES_COUNT / 3) {
                        gActiveMessageBank = 0;
                    }
                    MESSAGES_GET();
                }
            } else if (gEnteringSMS == SMS_ENTERING_MESSAGE) {
                dataPTR++;
                //if (dataPTR - dataPacket.data >= DataPacketDataSize) {
                if (dataPTR - dataPacket.data >= 19) {
                    dataPTR = dataPacket.data;
                }
            }
            break;
        case KEY_DOWN:
            if (gEnteringSMS != SMS_NOT_ENTERING) {
                if (bKeyPressed) {
                    gActiveMessageBank--;
                    gActiveMessage = gActiveMessageBank * 3;
                    if (gActiveMessage >= MESSAGES_COUNT) {
                        gActiveMessage = MESSAGES_COUNT - 1;
                    }
                    if (gActiveMessageBank > MESSAGES_COUNT / 3) {
                        gActiveMessageBank = MESSAGES_COUNT / 3 - 1;
                    }
                    MESSAGES_GET();
                }
            } else if (gEnteringSMS == SMS_ENTERING_MESSAGE) {
                if (dataPacket.data < dataPTR) {
                    dataPTR--;
                }
            }
            break;
        case KEY_EXIT:
            if (gEnteringSMS != SMS_NOT_ENTERING) {
                if (bKeyHeld) {
                    if (bKeyPressed) {
                        gEnteringSMS = SMS_NOT_ENTERING;
                        dataPTR = dataPacket.data;
                        memset(dataPacket.data, 0, DataPacketDataSize);
                    }
                } else {
                    if (bKeyPressed) {
                        if (gEnteringSMS == SMS_ENTERING_MESSAGE) {
                            if (dataPacket.data <= dataPTR) {
                                *dataPTR = '\0';
                                if (dataPacket.data < dataPTR) {
                                    dataPTR--;
                                }
                                *dataPTR = '\0';
                            }
                        } else if (gEnteringSMS == SMS_ENTERING_DEST) {
                            dataPacket.dest /= 10;
                        }
                    }
                }
            } else {
                if (bKeyPressed) {
                    gRequestDisplayScreen = DISPLAY_MAIN;
                }
            }
            updatePrevChar(Key);
            break;
        default:
            if (!bKeyHeld && bKeyPressed)
                gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
            break;
    }
}