#include "psa.h"

#define TAG "PSAProtocol"

static const SubGhzBlockConst subghz_protocol_psa_const = {
    .te_short = 250,
    .te_long = 500,
    .te_delta = 100,
    .min_count_bit_for_found = 128,
};

#define PSA_TE_SHORT_125        0x7d
#define PSA_TE_LONG_250         0xfa
#define PSA_TE_END_1000         1000
#define PSA_TE_END_500          500
#define PSA_TOLERANCE_99        99
#define PSA_TOLERANCE_100       100
#define PSA_TOLERANCE_49        0x31
#define PSA_TOLERANCE_50        0x32
#define PSA_PATTERN_THRESHOLD_1 0x46
#define PSA_PATTERN_THRESHOLD_2 0x45
#define PSA_MAX_BITS            0x79
#define PSA_KEY1_BITS           0x40
#define PSA_KEY2_BITS           0x50

#define TEA_DELTA  0x9E3779B9U
#define TEA_ROUNDS 32

#define PSA_BF1_CONST_U4 0x0E0F5C41U
#define PSA_BF1_CONST_U5 0x0F5C4123U

static const uint32_t PSA_BF1_KEY_SCHEDULE[4] = {
    0x4A434915U,
    0xD6743C2BU,
    0x1F29D308U,
    0xE6B79A64U,
};

static const uint32_t PSA_BF2_KEY_SCHEDULE[4] = {
    0x4039C240U,
    0xEDA92CABU,
    0x4306C02AU,
    0x02192A04U,
};

#define PSA_BF1_START 0x23000000U
#define PSA_BF1_END   0x24000000U
#define PSA_BF2_START 0xF3000000U
#define PSA_BF2_END   0xF4000000U

typedef enum {
    PSADecoderState0 = 0,
    PSADecoderState1 = 1,
    PSADecoderState2 = 2,
    PSADecoderState3 = 3,
    PSADecoderState4 = 4,
} PSADecoderState;

struct SubGhzProtocolDecoderPSA {
    SubGhzProtocolDecoderBase base;
    SubGhzBlockDecoder decoder;

    uint32_t state;
    uint32_t prev_duration;

    uint32_t decode_data_low;
    uint32_t decode_data_high;
    uint8_t decode_count_bit;

    uint32_t seed;
    uint32_t key1_low;
    uint32_t key1_high;
    uint16_t validation_field;
    uint32_t key2_low;
    uint32_t key2_high;

    uint32_t status_flag;
    uint16_t decrypted;
    uint8_t mode_serialize;

    uint16_t pattern_counter;
    ManchesterState manchester_state;

    uint8_t decrypted_button;
    uint32_t decrypted_serial;
    uint32_t decrypted_counter;
    uint16_t decrypted_crc;
    uint32_t decrypted_seed;
    uint8_t decrypted_type;
};

#ifdef ENABLE_EMULATE_FEATURE
struct SubGhzProtocolEncoderPSA {
    SubGhzProtocolEncoderBase base;
    SubGhzProtocolBlockEncoder encoder;
    SubGhzBlockGeneric generic;

    uint32_t key1_low;
    uint32_t key1_high;
    uint16_t validation_field;
    uint32_t key2_low;
    uint32_t counter;
    uint8_t button;
    uint8_t type;
    uint8_t seed;
    uint8_t mode;
    uint32_t serial;
    uint16_t crc;
    bool is_running;
};
#endif
const SubGhzProtocolDecoder subghz_protocol_psa_decoder = {
    .alloc = subghz_protocol_decoder_psa_alloc,
    .free = subghz_protocol_decoder_psa_free,
    .feed = subghz_protocol_decoder_psa_feed,
    .reset = subghz_protocol_decoder_psa_reset,
    .get_hash_data = subghz_protocol_decoder_psa_get_hash_data,
    .serialize = subghz_protocol_decoder_psa_serialize,
    .deserialize = subghz_protocol_decoder_psa_deserialize,
    .get_string = subghz_protocol_decoder_psa_get_string,
};
#ifdef ENABLE_EMULATE_FEATURE
const SubGhzProtocolEncoder subghz_protocol_psa_encoder = {
    .alloc = subghz_protocol_encoder_psa_alloc,
    .free = subghz_protocol_encoder_psa_free,
    .deserialize = subghz_protocol_encoder_psa_deserialize,
    .stop = subghz_protocol_encoder_psa_stop,
    .yield = subghz_protocol_encoder_psa_yield,
};
#else
const SubGhzProtocolEncoder subghz_protocol_psa_encoder = {
    .alloc = NULL,
    .free = NULL,
    .deserialize = NULL,
    .stop = NULL,
    .yield = NULL,
};
#endif
const SubGhzProtocol psa_protocol = {
    .name = PSA_PROTOCOL_NAME,
    .type = SubGhzProtocolTypeDynamic,
    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable |
            SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Load,
    .decoder = &subghz_protocol_psa_decoder,
    .encoder = &subghz_protocol_psa_encoder,
};

static void psa_setup_byte_buffer(
    uint8_t* buffer,
    uint32_t key1_low,
    uint32_t key1_high,
    uint32_t key2_low);
static void psa_calculate_checksum(uint8_t* buffer);
static uint8_t psa_calculate_tea_crc(uint32_t v0, uint32_t v1);
static void psa_tea_encrypt(uint32_t* v0, uint32_t* v1, const uint32_t* key);
static void psa_unpack_tea_result_to_buffer(uint8_t* buffer, uint32_t v0, uint32_t v1);

#ifdef ENABLE_EMULATE_FEATURE
static void psa_second_stage_xor_encrypt(uint8_t* buffer) {
    uint8_t E6 = buffer[8];
    uint8_t E7 = buffer[9];

    uint8_t P[6];
    P[0] = buffer[2];
    P[1] = buffer[3];
    P[2] = buffer[4];
    P[3] = buffer[5];
    P[4] = buffer[6];
    P[5] = buffer[7];

    uint8_t E5 = P[5] ^ E7 ^ E6;
    uint8_t E0 = P[2] ^ E5;
    uint8_t E2 = P[4] ^ E0;
    uint8_t E4 = P[3] ^ E2;
    uint8_t E3 = P[0] ^ E5;
    uint8_t E1 = P[1] ^ E3;

    buffer[2] = E0;
    buffer[3] = E1;
    buffer[4] = E2;
    buffer[5] = E3;
    buffer[6] = E4;
    buffer[7] = E5;
}

static void psa_build_buffer_mode23(
    SubGhzProtocolEncoderPSA* instance,
    uint8_t* buffer,
    uint8_t* preserve_buffer01) {
    FURI_LOG_I(TAG, "=== MODE 0x23 ENCRYPTION ===");
    FURI_LOG_I(
        TAG,
        "Input: Ser:%06lX Cnt:%08lX CRC:%02X Btn:%01X",
        (unsigned long)instance->serial,
        (unsigned long)instance->counter,
        (unsigned int)instance->crc,
        (unsigned int)instance->button);

    memset(buffer, 0, 48);

    buffer[2] = (uint8_t)((instance->serial >> 16) & 0xFF);
    buffer[3] = (uint8_t)((instance->serial >> 8) & 0xFF);
    buffer[4] = (uint8_t)(instance->serial & 0xFF);
    buffer[5] = (uint8_t)((instance->counter >> 8) & 0xFF);
    buffer[6] = (uint8_t)(instance->counter & 0xFF);
    buffer[7] = (uint8_t)(instance->crc & 0xFF);
    buffer[8] = (uint8_t)(instance->button & 0xF);

    uint8_t original_buffer9 = 0;
#ifndef REMOVE_LOGS
    uint8_t original_buffer8 = 0;
#endif
    bool has_original_key2 = (instance->key2_low != 0);
    if(has_original_key2) {
        original_buffer9 = (uint8_t)(instance->key2_low & 0xFF);
#ifndef REMOVE_LOGS
        original_buffer8 = (uint8_t)((instance->key2_low >> 8) & 0xFF);
#endif
        buffer[9] = original_buffer9;
        FURI_LOG_D(
            TAG,
            "Original Key2: 0x%04X, buffer[8]=0x%02X buffer[9]=0x%02X, preserving buffer[9]",
            (unsigned int)instance->key2_low,
            original_buffer8,
            original_buffer9);
    } else {
        FURI_LOG_D(TAG, "No original Key2, will find valid buffer[9]");
    }

    FURI_LOG_D(
        TAG,
        "Plaintext buffer[2-9]: %02X %02X %02X %02X %02X %02X %02X %02X",
        buffer[2],
        buffer[3],
        buffer[4],
        buffer[5],
        buffer[6],
        buffer[7],
        buffer[8],
        buffer[9]);

    uint8_t initial_plaintext[6];
    initial_plaintext[0] = buffer[2];
    initial_plaintext[1] = buffer[3];
    initial_plaintext[2] = buffer[4];
    initial_plaintext[3] = buffer[5];
    initial_plaintext[4] = buffer[6];
    initial_plaintext[5] = buffer[7];
    uint8_t initial_button = buffer[8] & 0xF;

    bool found = false;
    uint8_t buffer9_to_use = has_original_key2 ? original_buffer9 : 0;
    uint8_t buffer9_end = has_original_key2 ? original_buffer9 + 1 : 255;

    for(uint8_t buffer9_try = buffer9_to_use; buffer9_try < buffer9_end && !found; buffer9_try++) {
        for(uint8_t buffer8_high_try = 0; buffer8_high_try < 16 && !found; buffer8_high_try++) {
            buffer[2] = initial_plaintext[0];
            buffer[3] = initial_plaintext[1];
            buffer[4] = initial_plaintext[2];
            buffer[5] = initial_plaintext[3];
            buffer[6] = initial_plaintext[4];
            buffer[7] = initial_plaintext[5];
            buffer[8] = initial_button | (buffer8_high_try << 4);
            buffer[9] = buffer9_try;

            psa_second_stage_xor_encrypt(buffer);

            psa_calculate_checksum(buffer);
            uint8_t checksum_after = buffer[11];
            uint8_t key2_high_after = checksum_after & 0xF0;

            uint8_t validation = (checksum_after ^ buffer[8]) & 0xF0;
            if(validation == 0) {
                buffer[8] = (buffer[8] & 0x0F) | key2_high_after;
                buffer[13] = buffer[9] ^ buffer[8];
                found = true;
                FURI_LOG_D(
                    TAG,
                    "Found valid Key2: buffer[8]=0x%02X buffer[9]=0x%02X",
                    buffer[8],
                    buffer[9]);
                break;
            }
        }
    }

    if(!found) {
        FURI_LOG_W(TAG, "Brute force failed, using default approach");
        buffer[2] = initial_plaintext[0];
        buffer[3] = initial_plaintext[1];
        buffer[4] = initial_plaintext[2];
        buffer[5] = initial_plaintext[3];
        buffer[6] = initial_plaintext[4];
        buffer[7] = initial_plaintext[5];
        buffer[8] = initial_button;
        buffer[9] = has_original_key2 ? original_buffer9 : 0x23;

        psa_second_stage_xor_encrypt(buffer);
        psa_calculate_checksum(buffer);
        uint8_t checksum_after = buffer[11];
        uint8_t key2_high_after = checksum_after & 0xF0;
        buffer[8] = (buffer[8] & 0x0F) | key2_high_after;
        buffer[13] = buffer[9] ^ buffer[8];
    }

    if(preserve_buffer01 != NULL) {
        buffer[0] = preserve_buffer01[0];
        buffer[1] = preserve_buffer01[1];
        FURI_LOG_D(
            TAG, "Preserved buffer[0-1] from original Key1: %02X %02X", buffer[0], buffer[1]);
    } else {
        buffer[0] = buffer[2] ^ buffer[6];
        buffer[1] = buffer[3] ^ buffer[7];
        FURI_LOG_D(TAG, "Derived buffer[0-1]: %02X %02X", buffer[0], buffer[1]);
    }

    FURI_LOG_I(
        TAG,
        "Encrypted buffer[0-9]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
        buffer[0],
        buffer[1],
        buffer[2],
        buffer[3],
        buffer[4],
        buffer[5],
        buffer[6],
        buffer[7],
        buffer[8],
        buffer[9]);
}

static void psa_build_buffer_mode36(
    SubGhzProtocolEncoderPSA* instance,
    uint8_t* buffer,
    uint8_t* preserve_buffer01) {
    FURI_LOG_I(TAG, "=== MODE 0x36 ENCRYPTION ===");
    FURI_LOG_I(
        TAG,
        "Input: Ser:%06lX Cnt:%08lX CRC:%02X Btn:%01X",
        (unsigned long)instance->serial,
        (unsigned long)instance->counter,
        (unsigned int)instance->crc,
        (unsigned int)instance->button);

    memset(buffer, 0, 48);

    uint32_t v0 = ((instance->serial & 0xFFFFFF) << 8) | ((instance->counter >> 24) & 0xFF);
    uint32_t v1 = ((instance->counter & 0xFFFFFF) << 8) | ((instance->button & 0xF) << 4) |
                  (instance->crc & 0xFF);

    FURI_LOG_D(
        TAG, "Packed v0:0x%08lX v1:0x%08lX (before CRC)", (unsigned long)v0, (unsigned long)v1);

    uint8_t crc = psa_calculate_tea_crc(v0, v1);
    v1 = (v1 & 0xFFFFFF00) | crc;

    FURI_LOG_D(
        TAG, "Calculated CRC: 0x%02X, v1 after CRC: 0x%08lX", (unsigned int)crc, (unsigned long)v1);

    uint32_t bf_counter = PSA_BF1_START | (instance->serial & 0xFFFFFF);
    FURI_LOG_D(TAG, "BF counter: 0x%08lX (BF1_START | serial)", (unsigned long)bf_counter);

    uint32_t working_key[4];

    uint32_t wk2 = PSA_BF1_CONST_U4;
    uint32_t wk3 = bf_counter;
    psa_tea_encrypt(&wk2, &wk3, PSA_BF1_KEY_SCHEDULE);

    uint32_t wk0 = (bf_counter << 8) | 0x0E;
    uint32_t wk1 = PSA_BF1_CONST_U5;
    psa_tea_encrypt(&wk0, &wk1, PSA_BF1_KEY_SCHEDULE);

    working_key[0] = wk0;
    working_key[1] = wk1;
    working_key[2] = wk2;
    working_key[3] = wk3;

    psa_tea_encrypt(&v0, &v1, working_key);

    FURI_LOG_D(TAG, "TEA encrypted v0:0x%08lX v1:0x%08lX", (unsigned long)v0, (unsigned long)v1);
    FURI_LOG_D(
        TAG,
        "Working key: %08lX %08lX %08lX %08lX",
        (unsigned long)working_key[0],
        (unsigned long)working_key[1],
        (unsigned long)working_key[2],
        (unsigned long)working_key[3]);

    psa_unpack_tea_result_to_buffer(buffer, v0, v1);

    if(preserve_buffer01 != NULL) {
        buffer[0] = preserve_buffer01[0];
        buffer[1] = preserve_buffer01[1];
        FURI_LOG_D(
            TAG, "Preserved buffer[0-1] from original Key1: %02X %02X", buffer[0], buffer[1]);
    } else {
        buffer[0] = buffer[2] ^ buffer[6];
        buffer[1] = buffer[3] ^ buffer[7];
        FURI_LOG_D(TAG, "Derived buffer[0-1]: %02X %02X", buffer[0], buffer[1]);
    }

    FURI_LOG_I(
        TAG,
        "Encrypted buffer[0-9]: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
        buffer[0],
        buffer[1],
        buffer[2],
        buffer[3],
        buffer[4],
        buffer[5],
        buffer[6],
        buffer[7],
        buffer[8],
        buffer[9]);
}

static void psa_encoder_build_upload(SubGhzProtocolEncoderPSA* instance) {
    furi_check(instance);

    FURI_LOG_I(TAG, "=== ENCODER BUILD UPLOAD ===");
    FURI_LOG_I(
        TAG,
        "Mode: 0x%02X, Serial:%06lX Counter:%08lX CRC:%02X Button:%01X",
        (unsigned int)instance->mode,
        (unsigned long)instance->serial,
        (unsigned long)instance->counter,
        (unsigned int)instance->crc,
        (unsigned int)instance->button);

    uint8_t buffer[48] = {0};

    uint8_t preserve_buffer01[2] = {0};
    uint8_t* preserve_ptr = NULL;

    if(instance->key1_low != 0 || instance->key1_high != 0) {
        uint8_t orig_buffer[48] = {0};
        psa_setup_byte_buffer(
            orig_buffer, instance->key1_low, instance->key1_high, instance->key2_low);
        preserve_buffer01[0] = orig_buffer[0];
        preserve_buffer01[1] = orig_buffer[1];
        preserve_ptr = preserve_buffer01;
        FURI_LOG_D(
            TAG,
            "Original Key1: %08lX%08lX, preserving buffer[0-1]: %02X %02X",
            (unsigned long)instance->key1_high,
            (unsigned long)instance->key1_low,
            preserve_buffer01[0],
            preserve_buffer01[1]);
    } else {
        FURI_LOG_D(TAG, "No original Key1, will derive buffer[0-1]");
    }

    if(instance->mode == 0x23) {
        psa_build_buffer_mode23(instance, buffer, preserve_ptr);
    } else if(instance->mode == 0x36) {
        psa_build_buffer_mode36(instance, buffer, preserve_ptr);
    } else {
        FURI_LOG_E(TAG, "Unknown mode: 0x%02X", instance->mode);
        return;
    }

    uint32_t key1_high = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
                         ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
    uint32_t key1_low = ((uint32_t)buffer[4] << 24) | ((uint32_t)buffer[5] << 16) |
                        ((uint32_t)buffer[6] << 8) | (uint32_t)buffer[7];
    uint16_t validation_field = ((uint16_t)buffer[8] << 8) | (uint16_t)buffer[9];

    FURI_LOG_I(TAG, "=== ENCRYPTED KEYS ===");
    FURI_LOG_I(TAG, "Key1: %08lX%08lX", (unsigned long)key1_high, (unsigned long)key1_low);
    FURI_LOG_I(TAG, "Key2: %04X", (unsigned int)validation_field);

    size_t index = 0;
    uint32_t te = PSA_TE_LONG_250;

    for(int i = 0; i < 80; i++) {
        if(index >= instance->encoder.size_upload - 2) break;
        instance->encoder.upload[index++] = level_duration_make(true, te);
        instance->encoder.upload[index++] = level_duration_make(false, te);
    }

    uint32_t te_long_transition = subghz_protocol_psa_const.te_long;
    if(index < instance->encoder.size_upload - 3) {
        instance->encoder.upload[index++] = level_duration_make(false, te);
        instance->encoder.upload[index++] = level_duration_make(true, te_long_transition);
        instance->encoder.upload[index++] = level_duration_make(false, te);
    }

    uint64_t key1_data = ((uint64_t)key1_high << 32) | key1_low;
    for(int bit = 63; bit >= 0; bit--) {
        if(index >= instance->encoder.size_upload - 2) break;
        bool bit_value = (key1_data >> bit) & 1;
        if(bit_value) {
            instance->encoder.upload[index++] = level_duration_make(true, te);
            instance->encoder.upload[index++] = level_duration_make(false, te);
        } else {
            instance->encoder.upload[index++] = level_duration_make(false, te);
            instance->encoder.upload[index++] = level_duration_make(true, te);
        }
    }

    for(int bit = 15; bit >= 0; bit--) {
        if(index >= instance->encoder.size_upload - 2) break;
        bool bit_value = (validation_field >> bit) & 1;
        if(bit_value) {
            instance->encoder.upload[index++] = level_duration_make(true, te);
            instance->encoder.upload[index++] = level_duration_make(false, te);
        } else {
            instance->encoder.upload[index++] = level_duration_make(false, te);
            instance->encoder.upload[index++] = level_duration_make(true, te);
        }
    }

    uint32_t end_duration = PSA_TE_END_1000;
    if(index < instance->encoder.size_upload - 1) {
        instance->encoder.upload[index++] = level_duration_make(true, end_duration);
        instance->encoder.upload[index++] = level_duration_make(false, end_duration);
    }

    instance->encoder.size_upload = index;
    instance->encoder.front = 0;
    instance->encoder.repeat = 10;

    FURI_LOG_I(TAG, "=== TRANSMISSION PARAMETERS ===");
    FURI_LOG_I(
        TAG,
        "TE: %lu, TE_LONG_TRANS: %lu, TE_END: %lu",
        (unsigned long)te,
        (unsigned long)te_long_transition,
        (unsigned long)end_duration);
    FURI_LOG_I(
        TAG,
        "Upload size: %zu levels, Repeat: %d",
        instance->encoder.size_upload,
        instance->encoder.repeat);
    FURI_LOG_I(TAG, "Key1 data (64-bit): %016llX", (unsigned long long)key1_data);
    FURI_LOG_I(TAG, "Key2 data (16-bit): %04X", (unsigned int)validation_field);
    FURI_LOG_I(TAG, "=== END ENCODER BUILD ===");
}

void* subghz_protocol_encoder_psa_alloc(SubGhzEnvironment* environment) {
    UNUSED(environment);
    SubGhzProtocolEncoderPSA* instance = malloc(sizeof(SubGhzProtocolEncoderPSA));

    if(instance) {
        memset(instance, 0, sizeof(SubGhzProtocolEncoderPSA));
        instance->base.protocol = &psa_protocol;
        instance->generic.protocol_name = instance->base.protocol->name;

        instance->encoder.size_upload = 600;
        instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
        instance->encoder.repeat = 10;
        instance->encoder.front = 0;
        instance->encoder.is_running = false;
        instance->is_running = false;
    }

    return instance;
}

void subghz_protocol_encoder_psa_free(void* context) {
    furi_check(context);
    SubGhzProtocolEncoderPSA* instance = context;

    if(instance->encoder.upload) {
        free(instance->encoder.upload);
    }
    free(instance);
}

SubGhzProtocolStatus
    subghz_protocol_encoder_psa_deserialize(void* context, FlipperFormat* flipper_format) {
    furi_check(context);
    SubGhzProtocolEncoderPSA* instance = context;

    FURI_LOG_I(TAG, "=== ENCODER DESERIALIZE ===");

    SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
    FuriString* temp_str = furi_string_alloc();
    uint8_t hex_buffer[8];

    do {
        if(!flipper_format_read_string(flipper_format, "Key", temp_str)) {
            if(!flipper_format_read_hex(flipper_format, "Key1", hex_buffer, 8)) {
                FURI_LOG_E(TAG, "Failed to read Key1");
                break;
            }
            instance->key1_low = ((uint32_t)hex_buffer[0] << 24) |
                                 ((uint32_t)hex_buffer[1] << 16) | ((uint32_t)hex_buffer[2] << 8) |
                                 (uint32_t)hex_buffer[3];
            instance->key1_high = ((uint32_t)hex_buffer[4] << 24) |
                                  ((uint32_t)hex_buffer[5] << 16) |
                                  ((uint32_t)hex_buffer[6] << 8) | (uint32_t)hex_buffer[7];
        } else {
            const char* key_str = furi_string_get_cstr(temp_str);
            uint64_t key1 = 0;
            size_t str_len = strlen(key_str);
            for(size_t i = 0; i < str_len && i < 16; i++) {
                char c = key_str[i];
                if(c == ' ') continue;
                uint8_t nibble;
                if(c >= '0' && c <= '9') {
                    nibble = c - '0';
                } else if(c >= 'A' && c <= 'F') {
                    nibble = c - 'A' + 10;
                } else if(c >= 'a' && c <= 'f') {
                    nibble = c - 'a' + 10;
                } else {
                    break;
                }
                key1 = (key1 << 4) | nibble;
            }
            instance->key1_low = (uint32_t)(key1 & 0xFFFFFFFF);
            instance->key1_high = (uint32_t)((key1 >> 32) & 0xFFFFFFFF);
        }

        flipper_format_rewind(flipper_format);
        if(flipper_format_read_string(flipper_format, "Key_2", temp_str)) {
            const char* key2_str = furi_string_get_cstr(temp_str);
            uint64_t key2 = 0;
            size_t str_len = strlen(key2_str);
            for(size_t i = 0; i < str_len && i < 16; i++) {
                char c = key2_str[i];
                if(c == ' ') continue;
                uint8_t nibble;
                if(c >= '0' && c <= '9') {
                    nibble = c - '0';
                } else if(c >= 'A' && c <= 'F') {
                    nibble = c - 'A' + 10;
                } else if(c >= 'a' && c <= 'f') {
                    nibble = c - 'a' + 10;
                } else {
                    break;
                }
                key2 = (key2 << 4) | nibble;
            }
            instance->key2_low = (uint32_t)(key2 & 0xFFFFFFFF);
            instance->validation_field = (uint16_t)(key2 & 0xFFFF);
        } else {
            uint32_t val_field_val;
            if(flipper_format_read_uint32(flipper_format, "ValidationField", &val_field_val, 1)) {
                instance->validation_field = (uint16_t)(val_field_val & 0xFFFF);
                instance->key2_low = instance->validation_field;
            } else {
                uint8_t val_field[2];
                if(flipper_format_read_hex(flipper_format, "ValidationField", val_field, 2)) {
                    instance->validation_field = ((uint16_t)val_field[0] << 8) | val_field[1];
                    instance->key2_low = instance->validation_field;
                } else {
                    FURI_LOG_E(TAG, "ValidationField not found");
                    break;
                }
            }
        }

        flipper_format_rewind(flipper_format);
        if(!flipper_format_read_uint32(flipper_format, "Serial", &instance->serial, 1)) {
            FURI_LOG_E(TAG, "Serial not found");
            break;
        }

        flipper_format_rewind(flipper_format);
        if(!flipper_format_read_uint32(flipper_format, "Cnt", &instance->counter, 1)) {
            FURI_LOG_E(TAG, "Counter not found");
            break;
        }

        flipper_format_rewind(flipper_format);
        uint32_t btn_val = 0;
        if(!flipper_format_read_uint32(flipper_format, "Btn", &btn_val, 1)) {
            FURI_LOG_E(TAG, "Button not found");
            break;
        }
        instance->button = (uint8_t)(btn_val & 0xFF);

        flipper_format_rewind(flipper_format);
        uint32_t type_val = 0;
        if(!flipper_format_read_uint32(flipper_format, "Type", &type_val, 1)) {
            FURI_LOG_E(TAG, "Type not found");
            break;
        }
        instance->type = (uint8_t)(type_val & 0xFF);

        flipper_format_rewind(flipper_format);
        uint32_t crc_val = 0;
        if(!flipper_format_read_uint32(flipper_format, "CRC", &crc_val, 1)) {
            FURI_LOG_E(TAG, "CRC not found");
            break;
        }
        instance->crc = (uint16_t)(crc_val & 0xFFFF);

        flipper_format_rewind(flipper_format);
        uint32_t seed_val = 0;
        if(!flipper_format_read_uint32(flipper_format, "Seed", &seed_val, 1)) {
            FURI_LOG_E(TAG, "Seed not found");
            break;
        }
        instance->seed = (uint8_t)(seed_val & 0xFF);

        instance->mode = instance->type;
        if(instance->mode == 0x23 || instance->mode == 0) {
            instance->mode = 0x23;
        } else if(instance->mode == 0x36) {
            instance->mode = 0x36;
        } else {
            instance->mode = 0x23;
        }

        FURI_LOG_I(TAG, "=== LOADED VALUES ===");
        FURI_LOG_I(
            TAG,
            "Key1: %08lX%08lX",
            (unsigned long)instance->key1_high,
            (unsigned long)instance->key1_low);
        FURI_LOG_I(
            TAG,
            "Key2: %04X (validation_field: %04X)",
            (unsigned int)instance->key2_low,
            (unsigned int)instance->validation_field);
        FURI_LOG_I(
            TAG,
            "Serial: %06lX, Counter: %08lX, CRC: %02X, Button: %01X, Type/Mode: 0x%02X",
            (unsigned long)instance->serial,
            (unsigned long)instance->counter,
            (unsigned int)instance->crc,
            (unsigned int)instance->button,
            (unsigned int)instance->mode);

        psa_encoder_build_upload(instance);

        instance->is_running = true;
        ret = SubGhzProtocolStatusOk;
    } while(false);

    furi_string_free(temp_str);
    return ret;
}

void subghz_protocol_encoder_psa_stop(void* context) {
    furi_check(context);
    SubGhzProtocolEncoderPSA* instance = context;
    instance->is_running = false;
    instance->encoder.is_running = false;
}

LevelDuration subghz_protocol_encoder_psa_yield(void* context) {
    furi_check(context);
    SubGhzProtocolEncoderPSA* instance = context;

    if(!instance->is_running || instance->encoder.size_upload == 0) {
        instance->is_running = false;
        return level_duration_reset();
    }

    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
    instance->encoder.front++;

    if(instance->encoder.front >= instance->encoder.size_upload) {
        instance->encoder.front = 0;
        instance->encoder.repeat--;
        if(instance->encoder.repeat <= 0) {
            instance->is_running = false;
        }
    }

    return ret;
}
#endif
static uint32_t psa_abs_diff(uint32_t a, uint32_t b) {
    if(a < b) {
        return b - a;
    } else {
        return a - b;
    }
}

static void psa_setup_byte_buffer(
    uint8_t* buffer,
    uint32_t key1_low,
    uint32_t key1_high,
    uint32_t key2_low) {
    for(int i = 0; i < 8; i++) {
        int shift = i * 8;
        uint8_t byte_val;
        if(shift < 32) {
            byte_val = (uint8_t)((key1_low >> shift) & 0xFF);
        } else {
            byte_val = (uint8_t)((key1_high >> (shift - 32)) & 0xFF);
        }
        buffer[7 - i] = byte_val;
    }
    buffer[9] = (uint8_t)(key2_low & 0xFF);
    buffer[8] = (uint8_t)((key2_low >> 8) & 0xFF);
}

static void psa_calculate_checksum(uint8_t* buffer) {
    uint32_t checksum = 0;
    for(int i = 2; i < 8; i++) {
        checksum += (buffer[i] & 0xF) + ((buffer[i] >> 4) & 0xF);
    }
    buffer[11] = (uint8_t)((checksum * 0x10) & 0xFF);
}

static void psa_copy_reverse(uint8_t* temp, uint8_t* source) {
    temp[0] = source[5];
    temp[1] = source[4];
    temp[2] = source[3];
    temp[3] = source[2];
    temp[4] = source[9];
    temp[5] = source[8];
    temp[6] = source[7];
    temp[7] = source[6];
}

static void psa_second_stage_xor_decrypt(uint8_t* buffer) {
    uint8_t temp[8];
    psa_copy_reverse(temp, buffer);
    buffer[2] = temp[0] ^ temp[6];
    buffer[3] = temp[2] ^ temp[0];
    buffer[4] = temp[6] ^ temp[3];
    buffer[5] = temp[7] ^ temp[1];
    buffer[6] = temp[3] ^ temp[1];
    buffer[7] = temp[6] ^ temp[4] ^ temp[5];
}

static void psa_tea_encrypt(uint32_t* v0, uint32_t* v1, const uint32_t* key) {
    uint32_t sum = 0;
    for(int i = 0; i < TEA_ROUNDS; i++) {
        uint32_t k_idx1 = sum & 3;
        uint32_t temp = key[k_idx1] + sum;
        sum = sum + TEA_DELTA;
        *v0 = *v0 + (temp ^ (((*v1 >> 5) ^ (*v1 << 4)) + *v1));
        uint32_t k_idx2 = (sum >> 11) & 3;
        temp = key[k_idx2] + sum;
        *v1 = *v1 + (temp ^ (((*v0 >> 5) ^ (*v0 << 4)) + *v0));
    }
}

static void psa_tea_decrypt(uint32_t* v0, uint32_t* v1, const uint32_t* key) {
    uint32_t sum = TEA_DELTA * TEA_ROUNDS;
    for(int i = 0; i < TEA_ROUNDS; i++) {
        uint32_t k_idx2 = (sum >> 11) & 3;
        uint32_t temp = key[k_idx2] + sum;
        sum = sum - TEA_DELTA;
        *v1 = *v1 - (temp ^ (((*v0 >> 5) ^ (*v0 << 4)) + *v0));
        uint32_t k_idx1 = sum & 3;
        temp = key[k_idx1] + sum;
        *v0 = *v0 - (temp ^ (((*v1 >> 5) ^ (*v1 << 4)) + *v1));
    }
}

static void psa_prepare_tea_data(uint8_t* buffer, uint32_t* w0, uint32_t* w1) {
    *w0 = ((uint32_t)buffer[3] << 16) | ((uint32_t)buffer[2] << 24) | ((uint32_t)buffer[4] << 8) |
          (uint32_t)buffer[5];
    *w1 = ((uint32_t)buffer[7] << 16) | ((uint32_t)buffer[6] << 24) | ((uint32_t)buffer[8] << 8) |
          (uint32_t)buffer[9];
}

static uint8_t psa_calculate_tea_crc(uint32_t v0, uint32_t v1) {
    uint32_t crc = ((v0 >> 24) & 0xFF) + ((v0 >> 16) & 0xFF) + ((v0 >> 8) & 0xFF) + (v0 & 0xFF);
    crc += ((v1 >> 24) & 0xFF) + ((v1 >> 16) & 0xFF) + ((v1 >> 8) & 0xFF);
    return (uint8_t)(crc & 0xFF);
}

static uint16_t psa_calculate_crc16_bf2(uint8_t* buffer, int length) {
    uint16_t crc = 0;
    for(int i = 0; i < length; i++) {
        crc = crc ^ ((uint16_t)buffer[i] << 8);
        for(int j = 0; j < 8; j++) {
            if(crc & 0x8000) {
                crc = (crc << 1) ^ 0x8005;
            } else {
                crc = crc << 1;
            }
            crc = crc & 0xFFFF;
        }
    }
    return crc & 0xFFFF;
}

static void psa_unpack_tea_result_to_buffer(uint8_t* buffer, uint32_t v0, uint32_t v1) {
    buffer[2] = (uint8_t)((v0 >> 24) & 0xFF);
    buffer[3] = (uint8_t)((v0 >> 16) & 0xFF);
    buffer[4] = (uint8_t)((v0 >> 8) & 0xFF);
    buffer[5] = (uint8_t)(v0 & 0xFF);
    buffer[6] = (uint8_t)((v1 >> 24) & 0xFF);
    buffer[7] = (uint8_t)((v1 >> 16) & 0xFF);
    buffer[8] = (uint8_t)((v1 >> 8) & 0xFF);
    buffer[9] = (uint8_t)(v1 & 0xFF);
}

static void psa_extract_fields_mode23(uint8_t* buffer, SubGhzProtocolDecoderPSA* instance) {
    instance->decrypted_button = buffer[8] & 0xF;
    instance->decrypted_serial = ((uint32_t)buffer[3] << 8) | ((uint32_t)buffer[2] << 16) |
                                 (uint32_t)buffer[4];
    instance->decrypted_counter = (uint32_t)buffer[6] | ((uint32_t)buffer[5] << 8);
    instance->decrypted_crc = (uint16_t)buffer[7];
    instance->decrypted_type = 0x23;
    instance->decrypted_seed = instance->decrypted_serial;
}

static void psa_extract_fields_mode36(uint8_t* buffer, SubGhzProtocolDecoderPSA* instance) {
    instance->decrypted_button = (buffer[5] >> 4) & 0xF;
    instance->decrypted_serial = ((uint32_t)buffer[3] << 8) | ((uint32_t)buffer[2] << 16) |
                                 (uint32_t)buffer[4];
    instance->decrypted_counter = ((uint32_t)buffer[7] << 8) | ((uint32_t)buffer[6] << 16) |
                                  (uint32_t)buffer[8] | (((uint32_t)buffer[5] & 0xF) << 24);
    instance->decrypted_crc = (uint16_t)buffer[9];
    instance->decrypted_type = 0x36;
    instance->decrypted_seed = instance->decrypted_serial;
}

static bool psa_brute_force_decrypt_bf1(
    SubGhzProtocolDecoderPSA* instance,
    uint8_t* buffer,
    uint32_t w0,
    uint32_t w1) {
    for(uint32_t counter = PSA_BF1_START; counter < PSA_BF1_END; counter++) {
        uint32_t wk2 = PSA_BF1_CONST_U4;
        uint32_t wk3 = counter;
        psa_tea_encrypt(&wk2, &wk3, PSA_BF1_KEY_SCHEDULE);

        uint32_t wk0 = (counter << 8) | 0x0E;
        uint32_t wk1 = PSA_BF1_CONST_U5;
        psa_tea_encrypt(&wk0, &wk1, PSA_BF1_KEY_SCHEDULE);

        uint32_t working_key[4] = {wk0, wk1, wk2, wk3};

        uint32_t dec_v0 = w0;
        uint32_t dec_v1 = w1;
        psa_tea_decrypt(&dec_v0, &dec_v1, working_key);

        if((counter & 0xFFFFFF) == (dec_v0 >> 8)) {
            uint8_t crc = psa_calculate_tea_crc(dec_v0, dec_v1);
            if(crc == (dec_v1 & 0xFF)) {
                psa_unpack_tea_result_to_buffer(buffer, dec_v0, dec_v1);
                psa_extract_fields_mode36(buffer, instance);
                return true;
            }
        }
    }
    return false;
}

static bool psa_brute_force_decrypt_bf2(
    SubGhzProtocolDecoderPSA* instance,
    uint8_t* buffer,
    uint32_t w0,
    uint32_t w1) {
    for(uint32_t counter = PSA_BF2_START; counter < PSA_BF2_END; counter++) {
        uint32_t working_key[4] = {
            PSA_BF2_KEY_SCHEDULE[0] ^ counter,
            PSA_BF2_KEY_SCHEDULE[1] ^ counter,
            PSA_BF2_KEY_SCHEDULE[2] ^ counter,
            PSA_BF2_KEY_SCHEDULE[3] ^ counter,
        };

        uint32_t dec_v0 = w0;
        uint32_t dec_v1 = w1;
        psa_tea_decrypt(&dec_v0, &dec_v1, working_key);

        if((counter & 0xFFFFFF) == (dec_v0 >> 8)) {
            psa_unpack_tea_result_to_buffer(buffer, dec_v0, dec_v1);

            uint8_t crc_buffer[6] = {
                (uint8_t)((dec_v0 >> 24) & 0xFF),
                (uint8_t)((dec_v0 >> 8) & 0xFF),
                (uint8_t)((dec_v0 >> 16) & 0xFF),
                (uint8_t)(dec_v0 & 0xFF),
                (uint8_t)((dec_v1 >> 24) & 0xFF),
                (uint8_t)((dec_v1 >> 16) & 0xFF),
            };
            uint16_t crc16 = psa_calculate_crc16_bf2(crc_buffer, 6);
            uint16_t expected_crc = (((dec_v1 >> 16) & 0xFF) << 8) | (dec_v1 & 0xFF);

            if(crc16 == expected_crc) {
                psa_extract_fields_mode36(buffer, instance);
                return true;
            }
        }
    }
    return false;
}

static bool psa_direct_xor_decrypt(SubGhzProtocolDecoderPSA* instance, uint8_t* buffer) {
    psa_calculate_checksum(buffer);
    uint8_t checksum = buffer[11];
    uint8_t key2_high = buffer[8];

    uint8_t validation_result = (checksum ^ key2_high) & 0xF0;
    FURI_LOG_D(
        TAG,
        "Direct XOR validation: checksum=0x%02X, key2_high=0x%02X, result=0x%02X",
        checksum,
        key2_high,
        validation_result);

    if(validation_result == 0) {
        buffer[13] = buffer[9] ^ buffer[8];
        psa_second_stage_xor_decrypt(buffer);
        psa_extract_fields_mode23(buffer, instance);
        FURI_LOG_D(TAG, "Direct XOR decryption completed");
        return true;
    }
    FURI_LOG_D(
        TAG,
        "Direct XOR validation FAILED: (checksum ^ key2_high) & 0xF0 = 0x%02X (expected 0x00)",
        validation_result);
    return false;
}

static void psa_decrypt_router(SubGhzProtocolDecoderPSA* instance) {
    FURI_LOG_I(TAG, "=== DECRYPTION ROUTER CALLED ===");
    FURI_LOG_I(
        TAG,
        "Key1:%08lX%08lX Key2:%04X mode_serialize:0x%02X decrypted:0x%02X",
        (unsigned long)instance->key1_high,
        (unsigned long)instance->key1_low,
        (unsigned int)(instance->key2_low & 0xFFFF),
        (unsigned int)instance->mode_serialize,
        (unsigned int)instance->decrypted);

    uint8_t buffer[48] = {0};

    psa_setup_byte_buffer(buffer, instance->key1_low, instance->key1_high, instance->key2_low);

    uint8_t mode = instance->mode_serialize;

    if(mode == 1 || mode == 2) {
        if(psa_direct_xor_decrypt(instance, buffer)) {
            mode = 0x23;
            FURI_LOG_I(TAG, "Converted mode %d -> 0x23 (Direct XOR)", instance->mode_serialize);
        } else {
            mode = 0x36;
            FURI_LOG_I(
                TAG, "Converted mode %d -> 0x36 (TEA Brute Force)", instance->mode_serialize);
        }
    }

    if(mode == 0x23) {
        FURI_LOG_I(TAG, "Attempting Direct XOR decryption (Type 0x23)");
        if(psa_direct_xor_decrypt(instance, buffer)) {
            instance->mode_serialize = 0x23;
            instance->decrypted = 0x50;
            FURI_LOG_I(TAG, "Direct XOR decryption SUCCESS");
            return;
        }
        FURI_LOG_W(TAG, "Direct XOR decryption FAILED");
    } else if(mode == 0x36) {
        FURI_LOG_I(TAG, "Attempting TEA brute force decryption (Type 0x36)");

        uint32_t w0, w1;
        psa_prepare_tea_data(buffer, &w0, &w1);
        FURI_LOG_D(
            TAG, "Prepared TEA data: w0=0x%08lX w1=0x%08lX", (unsigned long)w0, (unsigned long)w1);

        FURI_LOG_I(TAG, "Starting BF1 brute force...");
        if(psa_brute_force_decrypt_bf1(instance, buffer, w0, w1)) {
            instance->mode_serialize = 0x36;
            instance->decrypted = 0x50;
            FURI_LOG_I(
                TAG,
                "BF1 brute force SUCCESS - Btn:%02X Ser:%06lX Cnt:%08lX",
                (unsigned int)instance->decrypted_button,
                (unsigned long)instance->decrypted_serial,
                (unsigned long)instance->decrypted_counter);
            return;
        }
        FURI_LOG_W(TAG, "BF1 brute force FAILED - trying BF2...");
        if(psa_brute_force_decrypt_bf2(instance, buffer, w0, w1)) {
            instance->mode_serialize = 0x36;
            instance->decrypted = 0x50;
            FURI_LOG_I(
                TAG,
                "BF2 brute force SUCCESS - Btn:%02X Ser:%06lX Cnt:%08lX",
                (unsigned int)instance->decrypted_button,
                (unsigned long)instance->decrypted_serial,
                (unsigned long)instance->decrypted_counter);
            return;
        }
        FURI_LOG_E(TAG, "Both BF1 and BF2 brute force FAILED");
    } else {
        FURI_LOG_I(TAG, "Mode uninitialized (0x00) - trying direct XOR first");
        if(psa_direct_xor_decrypt(instance, buffer)) {
            instance->mode_serialize = 0x23;
            instance->decrypted = 0x50;
            FURI_LOG_I(TAG, "Direct XOR decryption SUCCESS");
            return;
        }

        FURI_LOG_I(TAG, "Direct XOR failed - trying brute force...");
        uint32_t w0, w1;
        psa_prepare_tea_data(buffer, &w0, &w1);

        if(psa_brute_force_decrypt_bf1(instance, buffer, w0, w1)) {
            instance->mode_serialize = 0x36;
            instance->decrypted = 0x50;
            FURI_LOG_I(TAG, "BF1 brute force SUCCESS");
            return;
        }
        if(psa_brute_force_decrypt_bf2(instance, buffer, w0, w1)) {
            instance->mode_serialize = 0x36;
            instance->decrypted = 0x50;
            FURI_LOG_I(TAG, "BF2 brute force SUCCESS");
            return;
        }
    }

    FURI_LOG_E(TAG, "=== ALL DECRYPTION ATTEMPTS FAILED ===");
    instance->decrypted = 0x00;
}

void* subghz_protocol_decoder_psa_alloc(SubGhzEnvironment* environment) {
    UNUSED(environment);
    SubGhzProtocolDecoderPSA* instance = malloc(sizeof(SubGhzProtocolDecoderPSA));
    if(instance) {
        memset(instance, 0, sizeof(SubGhzProtocolDecoderPSA));
        instance->base.protocol = &psa_protocol;
        instance->manchester_state = ManchesterStateMid1;
    }
    return instance;
}

void subghz_protocol_decoder_psa_free(void* context) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;
    free(instance);
}

void subghz_protocol_decoder_psa_reset(void* context) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;
    instance->state = 0;
    instance->status_flag = 0;
    instance->mode_serialize = 0;
    instance->key1_low = 0;
    instance->key1_high = 0;
    instance->key2_low = 0;
    instance->key2_high = 0;
    instance->decode_data_low = 0;
    instance->decode_data_high = 0;
    instance->decode_count_bit = 0;
    instance->pattern_counter = 0;
    instance->manchester_state = ManchesterStateMid1;
    instance->decrypted_button = 0;
    instance->decrypted_serial = 0;
    instance->decrypted_counter = 0;
    instance->decrypted_crc = 0;
    instance->decrypted_seed = 0;
    instance->decrypted_type = 0;
}

void subghz_protocol_decoder_psa_feed(void* context, bool level, uint32_t duration) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;

    uint32_t tolerance;
    uint32_t new_state = instance->state;
    uint32_t prev_dur = instance->prev_duration;
    uint32_t te_short = subghz_protocol_psa_const.te_short;
    uint32_t te_long = subghz_protocol_psa_const.te_long;

    switch(instance->state) {
    case PSADecoderState0:
        if(!level) {
            return;
        }

        if(duration < te_short) {
            tolerance = te_short - duration;
            if(tolerance > PSA_TOLERANCE_99) {
                if(duration < PSA_TE_SHORT_125) {
                    tolerance = PSA_TE_SHORT_125 - duration;
                } else {
                    tolerance = duration - PSA_TE_SHORT_125;
                }
                if(tolerance > 40) {
                    return;
                }
                if(duration > 180) {
                    return;
                }
                new_state = PSADecoderState3;
            } else {
                new_state = PSADecoderState1;
            }
        } else {
            tolerance = duration - te_short;
            if(tolerance > PSA_TOLERANCE_99) {
                return;
            }
            new_state = PSADecoderState1;
        }

        instance->decode_data_low = 0;
        instance->decode_data_high = 0;
        instance->pattern_counter = 0;
        instance->decode_count_bit = 0;
        instance->mode_serialize = 0;
        instance->prev_duration = duration;
        instance->decrypted_type = 0;
        instance->decrypted_button = 0;
        instance->decrypted_serial = 0;
        instance->decrypted_counter = 0;
        instance->decrypted_crc = 0;
        instance->decrypted_seed = 0;
        instance->decrypted = 0x00;
        manchester_advance(
            instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL);
        break;

    case PSADecoderState1:
        if(level) {
            return;
        }

        if(duration < te_short) {
            tolerance = te_short - duration;
            if(tolerance < PSA_TOLERANCE_100) {
                uint32_t prev_diff = psa_abs_diff(prev_dur, te_short);
                if(prev_diff <= PSA_TOLERANCE_99) {
                    instance->pattern_counter++;
                }
                instance->prev_duration = duration;
                return;
            }
        } else {
            tolerance = duration - te_short;
            if(tolerance < PSA_TOLERANCE_100) {
                uint32_t prev_diff = psa_abs_diff(prev_dur, te_short);
                if(prev_diff <= PSA_TOLERANCE_99) {
                    instance->pattern_counter++;
                }
                instance->prev_duration = duration;
                return;
            } else {
                uint32_t long_diff;
                if(duration < te_long) {
                    long_diff = te_long - duration;
                } else {
                    long_diff = duration - te_long;
                }
                if(long_diff < 100) {
                    if(instance->pattern_counter > PSA_PATTERN_THRESHOLD_1) {
                        FURI_LOG_I(
                            TAG,
                            "[State1->State2] Transition detected with pattern_cnt=%lu",
                            (unsigned long)instance->pattern_counter);
                        new_state = PSADecoderState2;
                        instance->decode_data_low = 0;
                        instance->decode_data_high = 0;
                        instance->decode_count_bit = 0;
                        manchester_advance(
                            instance->manchester_state,
                            ManchesterEventReset,
                            &instance->manchester_state,
                            NULL);
                        instance->state = new_state;
                    }
                    instance->pattern_counter = 0;
                    instance->prev_duration = duration;
                    return;
                }
            }
        }

        new_state = PSADecoderState0;
        instance->pattern_counter = 0;
        break;

    case PSADecoderState2:
        if(instance->decode_count_bit >= PSA_MAX_BITS) {
            new_state = PSADecoderState0;
            break;
        }

        if(level && instance->decode_count_bit == PSA_KEY2_BITS) {
            if(duration >= 800) {
                uint32_t end_diff;
                if(duration < PSA_TE_END_1000) {
                    end_diff = PSA_TE_END_1000 - duration;
                } else {
                    end_diff = duration - PSA_TE_END_1000;
                }
                if(end_diff <= 199) {
                    if(((instance->key1_high >> 16) & 0xF) != 0xA) {
                        instance->decode_data_low = 0;
                        instance->decode_data_high = 0;
                        instance->decode_count_bit = 0;
                        new_state = PSADecoderState0;
                        instance->state = new_state;
                        return;
                    }

                    uint32_t new_key2_low = instance->decode_data_low;
                    instance->validation_field = (uint16_t)(instance->decode_data_low & 0xFFFF);

                    instance->decrypted_type = 0;
                    instance->decrypted_button = 0;
                    instance->decrypted_serial = 0;
                    instance->decrypted_counter = 0;
                    instance->decrypted_crc = 0;
                    instance->decrypted_seed = 0;
                    instance->decrypted = 0x00;

                    instance->key2_low = new_key2_low;
                    instance->key2_high = instance->decode_data_high;
                    instance->mode_serialize = 1;
                    instance->status_flag = 0x80;

                    FURI_LOG_I(
                        TAG,
                        "Signal decoded - Key1:%08lX%08lX Key2:%04X ValField:%04X",
                        (unsigned long)instance->key1_high,
                        (unsigned long)instance->key1_low,
                        (unsigned int)(instance->key2_low & 0xFFFF),
                        (unsigned int)instance->validation_field);

                    uint8_t buffer[48] = {0};
                    psa_setup_byte_buffer(
                        buffer, instance->key1_low, instance->key1_high, instance->key2_low);
                    if(psa_direct_xor_decrypt(instance, buffer)) {
                        instance->mode_serialize = 0x23;
                        instance->decrypted = 0x50;
                        FURI_LOG_I(
                            TAG,
                            "Direct XOR decryption SUCCESS - Type:0x23 Btn:%02X Ser:%06lX Cnt:%08lX",
                            (unsigned int)instance->decrypted_button,
                            (unsigned long)instance->decrypted_serial,
                            (unsigned long)instance->decrypted_counter);
                    } else {
                        instance->decrypted = 0x00;
                        instance->mode_serialize = 0x36;
                        FURI_LOG_I(
                            TAG,
                            "Direct XOR decryption FAILED - marked for brute force (Type:0x36) - deferred to get_string");
                    }

                    if(instance->base.callback) {
                        instance->base.callback(&instance->base, instance->base.context);
                    }

                    instance->decode_data_low = 0;
                    instance->decode_data_high = 0;
                    instance->decode_count_bit = 0;
                    new_state = PSADecoderState0;
                    instance->state = new_state;
                    return;
                }
            }
        }

        uint8_t manchester_input = 0;
        bool should_process = false;

        if(duration < te_short) {
            tolerance = te_short - duration;
            if(tolerance >= PSA_TOLERANCE_100) {
                return;
            }
            manchester_input = ((level ^ 1) & 0x7f) << 1;
            should_process = true;
        } else {
            tolerance = duration - te_short;
            if(tolerance < PSA_TOLERANCE_100) {
                manchester_input = ((level ^ 1) & 0x7f) << 1;
                should_process = true;
            } else if(duration < te_long) {
                uint32_t diff_from_250 = duration - te_short;
                uint32_t diff_from_500 = te_long - duration;

                if(diff_from_500 < 150 || diff_from_250 > diff_from_500) {
                    if(level == 0) {
                        manchester_input = 6;
                    } else {
                        manchester_input = 4;
                    }
                    should_process = true;
                } else if(diff_from_250 < 150) {
                    manchester_input = ((level ^ 1) & 0x7f) << 1;
                    should_process = true;
                } else {
                    if(duration > 10000) {
                        new_state = PSADecoderState0;
                        instance->pattern_counter = 0;
                        return;
                    }
                    if(duration >= 350 && duration <= 400) {
                        if(level == 0) {
                            manchester_input = 6;
                        } else {
                            manchester_input = 4;
                        }
                        should_process = true;
                    } else {
                        return;
                    }
                }
            } else {
                uint32_t long_diff = duration - te_long;
                if(long_diff < 100) {
                    if(level == 0) {
                        manchester_input = 6;
                    } else {
                        manchester_input = 4;
                    }
                    should_process = true;
                } else {
                    if(!level) {
                        if(duration > 10000) {
                            new_state = PSADecoderState0;
                            instance->pattern_counter = 0;
                            return;
                        }
                        return;
                    }
                    should_process = false;
                }
            }
        }

        if(should_process && instance->decode_count_bit < PSA_KEY2_BITS) {
            bool decoded_bit = false;

            if(manchester_advance(
                   instance->manchester_state,
                   (ManchesterEvent)manchester_input,
                   &instance->manchester_state,
                   &decoded_bit)) {
                uint32_t carry = (instance->decode_data_low >> 31) & 1;
                instance->decode_data_low = (instance->decode_data_low << 1) |
                                            (decoded_bit ? 1 : 0);
                instance->decode_data_high = (instance->decode_data_high << 1) | carry;
                instance->decode_count_bit++;

                if(instance->decode_count_bit == PSA_KEY1_BITS) {
                    instance->key1_low = instance->decode_data_low;
                    instance->key1_high = instance->decode_data_high;
                    instance->decode_data_low = 0;
                    instance->decode_data_high = 0;
                }
            }
        }

        if(!level) {
            return;
        }

        if(!should_process) {
            uint32_t end_diff;
            if(duration < PSA_TE_END_1000) {
                end_diff = PSA_TE_END_1000 - duration;
            } else {
                end_diff = duration - PSA_TE_END_1000;
            }
            if(end_diff <= 199) {
                if(instance->decode_count_bit != PSA_KEY2_BITS) {
                    return;
                }

                if(((instance->key1_high >> 16) & 0xF) == 0xA) {
                    uint32_t new_key2_low = instance->decode_data_low;
                    instance->validation_field = (uint16_t)(instance->decode_data_low & 0xFFFF);

                    instance->decrypted_type = 0;
                    instance->decrypted_button = 0;
                    instance->decrypted_serial = 0;
                    instance->decrypted_counter = 0;
                    instance->decrypted_crc = 0;
                    instance->decrypted_seed = 0;
                    instance->decrypted = 0x00;

                    instance->key2_low = new_key2_low;
                    instance->key2_high = instance->decode_data_high;
                    instance->status_flag = 0x80;

                    FURI_LOG_I(
                        TAG,
                        "Signal decoded (alt path) - Key1:%08lX%08lX Key2:%04X ValField:%04X",
                        (unsigned long)instance->key1_high,
                        (unsigned long)instance->key1_low,
                        (unsigned int)(instance->key2_low & 0xFFFF),
                        (unsigned int)instance->validation_field);

                    uint8_t buffer[48] = {0};
                    psa_setup_byte_buffer(
                        buffer, instance->key1_low, instance->key1_high, instance->key2_low);
                    if(psa_direct_xor_decrypt(instance, buffer)) {
                        instance->mode_serialize = 0x23;
                        instance->decrypted = 0x50;
                        FURI_LOG_I(
                            TAG,
                            "Direct XOR decryption SUCCESS - Type:0x23 Btn:%02X Ser:%06lX Cnt:%08lX",
                            (unsigned int)instance->decrypted_button,
                            (unsigned long)instance->decrypted_serial,
                            (unsigned long)instance->decrypted_counter);
                    } else {
                        instance->decrypted = 0x00;
                        FURI_LOG_I(
                            TAG,
                            "Direct XOR decryption FAILED - marked for brute force (Type:0x36) - deferred to get_string");
                        instance->mode_serialize = 0x36;
                    }

                    if(instance->base.callback) {
                        instance->base.callback(&instance->base, instance->base.context);
                    }

                    instance->decode_data_low = 0;
                    instance->decode_data_high = 0;
                    instance->decode_count_bit = 0;
                    new_state = PSADecoderState0;
                } else {
                    return;
                }
            } else {
                return;
            }
        }
        break;

    case PSADecoderState3:
        if(duration >= 250) {
            if(duration >= PSA_TE_LONG_250 && duration < 0x12c) {
                if(instance->pattern_counter > PSA_PATTERN_THRESHOLD_2) {
                    FURI_LOG_I(
                        TAG,
                        "[State3->State4] Transition detected with pattern_cnt=%lu",
                        (unsigned long)instance->pattern_counter);
                    new_state = PSADecoderState4;
                    instance->decode_data_low = 0;
                    instance->decode_data_high = 0;
                    instance->decode_count_bit = 0;
                    manchester_advance(
                        instance->manchester_state,
                        ManchesterEventReset,
                        &instance->manchester_state,
                        NULL);
                    instance->state = new_state;
                    instance->pattern_counter = 0;
                    instance->prev_duration = duration;
                    return;
                }
            }
            new_state = PSADecoderState0;
            instance->pattern_counter = 0;
            break;
        }

        if(duration < PSA_TE_SHORT_125) {
            tolerance = PSA_TE_SHORT_125 - duration;
        } else {
            tolerance = duration - PSA_TE_SHORT_125;
        }

        if(tolerance < PSA_TOLERANCE_50) {
            uint32_t prev_diff = psa_abs_diff(prev_dur, PSA_TE_SHORT_125);
            if(prev_diff <= PSA_TOLERANCE_49) {
                instance->pattern_counter++;
            } else {
                instance->pattern_counter = 0;
            }
            instance->prev_duration = duration;
            return;
        }

        new_state = PSADecoderState0;
        instance->pattern_counter = 0;
        break;

    case PSADecoderState4:
        if(instance->decode_count_bit >= PSA_MAX_BITS) {
            new_state = PSADecoderState0;
            break;
        }

        if(!level) {
            uint8_t manchester_input;
            bool decoded_bit = false;

            if(duration < PSA_TE_SHORT_125) {
                tolerance = PSA_TE_SHORT_125 - duration;
                if(tolerance > PSA_TOLERANCE_49) {
                    return;
                }
                manchester_input = ((level ^ 1) & 0x7f) << 1;
            } else {
                tolerance = duration - PSA_TE_SHORT_125;
                if(tolerance < PSA_TOLERANCE_50) {
                    manchester_input = ((level ^ 1) & 0x7f) << 1;
                } else if(duration >= PSA_TE_LONG_250 && duration < 0x12c) {
                    if(level == 0) {
                        manchester_input = 6;
                    } else {
                        manchester_input = 4;
                    }
                } else {
                    return;
                }
            }

            if(manchester_advance(
                   instance->manchester_state,
                   (ManchesterEvent)manchester_input,
                   &instance->manchester_state,
                   &decoded_bit)) {
                uint32_t carry = (instance->decode_data_low >> 31) & 1;
                instance->decode_data_low = (instance->decode_data_low << 1) |
                                            (decoded_bit ? 1 : 0);
                instance->decode_data_high = (instance->decode_data_high << 1) | carry;
                instance->decode_count_bit++;

                if(instance->decode_count_bit == PSA_KEY1_BITS) {
                    instance->key1_low = instance->decode_data_low;
                    instance->key1_high = instance->decode_data_high;
                    instance->decode_data_low = 0;
                    instance->decode_data_high = 0;
                }
            }
        } else if(level) {
            uint32_t end_diff;
            if(duration < PSA_TE_END_500) {
                end_diff = PSA_TE_END_500 - duration;
            } else {
                end_diff = duration - PSA_TE_END_500;
            }
            if(end_diff <= 99) {
                if(instance->decode_count_bit != PSA_KEY2_BITS) {
                    return;
                }

                if(((instance->key1_high >> 16) & 0xF) != 0xA) {
                    instance->decode_data_low = 0;
                    instance->decode_data_high = 0;
                    instance->decode_count_bit = 0;
                    new_state = PSADecoderState0;
                    instance->state = new_state;
                    return;
                }

                uint32_t new_key2_low = instance->decode_data_low;
                instance->validation_field = (uint16_t)(instance->decode_data_low & 0xFFFF);

                instance->decrypted_type = 0;
                instance->decrypted_button = 0;
                instance->decrypted_serial = 0;
                instance->decrypted_counter = 0;
                instance->decrypted_crc = 0;
                instance->decrypted_seed = 0;
                instance->decrypted = 0x00;

                instance->key2_low = new_key2_low;
                instance->key2_high = instance->decode_data_high;
                instance->mode_serialize = 2;
                instance->status_flag = 0x80;

                FURI_LOG_I(
                    TAG,
                    "Signal decoded (state4) - Key1:%08lX%08lX Key2:%04X ValField:%04X",
                    (unsigned long)instance->key1_high,
                    (unsigned long)instance->key1_low,
                    (unsigned int)(instance->key2_low & 0xFFFF),
                    (unsigned int)instance->validation_field);

                uint8_t buffer[48] = {0};
                psa_setup_byte_buffer(
                    buffer, instance->key1_low, instance->key1_high, instance->key2_low);
                if(psa_direct_xor_decrypt(instance, buffer)) {
                    instance->mode_serialize = 0x23;
                    instance->decrypted = 0x50;
                    FURI_LOG_I(
                        TAG,
                        "Direct XOR decryption SUCCESS - Type:0x23 Btn:%02X Ser:%06lX Cnt:%08lX",
                        (unsigned int)instance->decrypted_button,
                        (unsigned long)instance->decrypted_serial,
                        (unsigned long)instance->decrypted_counter);
                } else {
                    instance->decrypted = 0x00;
                    instance->mode_serialize = 0x36;
                    FURI_LOG_I(
                        TAG,
                        "Direct XOR decryption FAILED - marked for brute force (Type:0x36) - deferred to get_string");
                }

                if(instance->base.callback) {
                    instance->base.callback(&instance->base, instance->base.context);
                }

                instance->decode_data_low = 0;
                instance->decode_data_high = 0;
                instance->decode_count_bit = 0;
                new_state = PSADecoderState0;
                instance->state = new_state;
                return;
            } else {
                return;
            }
        }
        break;
    }

    instance->state = new_state;
    instance->prev_duration = duration;
}

uint8_t subghz_protocol_decoder_psa_get_hash_data(void* context) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;
    uint64_t combined_data = ((uint64_t)instance->key1_high << 32) | instance->key1_low;
    SubGhzBlockDecoder decoder = {.decode_data = combined_data, .decode_count_bit = 64};
    return subghz_protocol_blocks_get_hash_data(&decoder, 16);
}

SubGhzProtocolStatus subghz_protocol_decoder_psa_serialize(
    void* context,
    FlipperFormat* flipper_format,
    SubGhzRadioPreset* preset) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;

    SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
    do {
        if(!flipper_format_write_uint32(flipper_format, "Frequency", &preset->frequency, 1)) break;

        if(!flipper_format_write_string_cstr(
               flipper_format, "Preset", furi_string_get_cstr(preset->name)))
            break;

        if(!flipper_format_write_string_cstr(
               flipper_format, "Protocol", instance->base.protocol->name))
            break;

        uint32_t bits = 128;
        if(!flipper_format_write_uint32(flipper_format, "Bit", &bits, 1)) break;

        char key1_str[20];
        uint64_t key1 = ((uint64_t)instance->key1_high << 32) | instance->key1_low;
        snprintf(key1_str, sizeof(key1_str), "%016llX", key1);
        if(!flipper_format_write_string_cstr(flipper_format, "Key", key1_str)) break;

        char key2_str[20];
        uint64_t key2 = ((uint64_t)instance->key2_high << 32) | instance->key2_low;
        snprintf(key2_str, sizeof(key2_str), "%016llX", key2);
        if(!flipper_format_write_string_cstr(flipper_format, "Key_2", key2_str)) break;

        uint32_t val_field = instance->validation_field;
        flipper_format_write_uint32(flipper_format, "ValidationField", &val_field, 1);

        if(instance->decrypted == 0x50 && instance->decrypted_type != 0) {
            flipper_format_write_uint32(flipper_format, "Serial", &instance->decrypted_serial, 1);

            uint32_t btn_temp = instance->decrypted_button;
            flipper_format_write_uint32(flipper_format, "Btn", &btn_temp, 1);

            flipper_format_write_uint32(flipper_format, "Cnt", &instance->decrypted_counter, 1);

            uint32_t crc_temp = instance->decrypted_crc;
            flipper_format_write_uint32(flipper_format, "CRC", &crc_temp, 1);

            uint32_t type_temp = instance->decrypted_type;
            flipper_format_write_uint32(flipper_format, "Type", &type_temp, 1);

            flipper_format_write_uint32(flipper_format, "Seed", &instance->decrypted_seed, 1);
        }

        ret = SubGhzProtocolStatusOk;
    } while(false);

    return ret;
}

SubGhzProtocolStatus
    subghz_protocol_decoder_psa_deserialize(void* context, FlipperFormat* flipper_format) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;

    SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
    FuriString* temp_str = furi_string_alloc();

    do {
        if(!flipper_format_read_string(flipper_format, "Key", temp_str)) {
            break;
        }

        const char* key1_str = furi_string_get_cstr(temp_str);
        uint64_t key1 = 0;
        size_t str_len = strlen(key1_str);
        for(size_t i = 0; i < str_len && i < 16; i++) {
            char c = key1_str[i];
            if(c == ' ') continue;

            uint8_t nibble;
            if(c >= '0' && c <= '9') {
                nibble = c - '0';
            } else if(c >= 'A' && c <= 'F') {
                nibble = c - 'A' + 10;
            } else if(c >= 'a' && c <= 'f') {
                nibble = c - 'a' + 10;
            } else {
                break;
            }
            key1 = (key1 << 4) | nibble;
        }
        instance->key1_low = (uint32_t)(key1 & 0xFFFFFFFF);
        instance->key1_high = (uint32_t)((key1 >> 32) & 0xFFFFFFFF);

        if(!flipper_format_read_string(flipper_format, "Key_2", temp_str)) {
            break;
        }

        const char* key2_str = furi_string_get_cstr(temp_str);
        uint64_t key2 = 0;
        str_len = strlen(key2_str);
        for(size_t i = 0; i < str_len && i < 16; i++) {
            char c = key2_str[i];
            if(c == ' ') continue;

            uint8_t nibble;
            if(c >= '0' && c <= '9') {
                nibble = c - '0';
            } else if(c >= 'A' && c <= 'F') {
                nibble = c - 'A' + 10;
            } else if(c >= 'a' && c <= 'f') {
                nibble = c - 'a' + 10;
            } else {
                break;
            }
            key2 = (key2 << 4) | nibble;
        }
        instance->key2_low = (uint32_t)(key2 & 0xFFFFFFFF);
        instance->key2_high = (uint32_t)((key2 >> 32) & 0xFFFFFFFF);

        instance->status_flag = 0x80;

        psa_decrypt_router(instance);

        ret = SubGhzProtocolStatusOk;
    } while(false);

    furi_string_free(temp_str);
    return ret;
}

void subghz_protocol_decoder_psa_get_string(void* context, FuriString* output) {
    furi_check(context);
    SubGhzProtocolDecoderPSA* instance = context;

    if(instance->status_flag == 0x80 && (instance->key1_low != 0 || instance->key1_high != 0) &&
       instance->decrypted_type == 0) {
        FURI_LOG_I(TAG, "get_string: Calling decryption router (decrypted_type=0)");
        psa_decrypt_router(instance);
    } else {
        FURI_LOG_D(
            TAG,
            "get_string: Skipping router - status_flag=0x%08lX decrypted_type=0x%02X",
            (unsigned long)instance->status_flag,
            (unsigned int)instance->decrypted_type);
    }

    uint16_t key2_value = (uint16_t)(instance->key2_low & 0xFFFF);

    if(instance->decrypted == 0x50 && instance->decrypted_type != 0) {
        if(instance->decrypted_type == 0x23) {
            furi_string_printf(
                output,
                "%s %dbit\r\n"
                "Key1:%08lX%08lX\r\n"
                "Key2:%04X\r\n"
                "Btn:%01X\r\n"
                "Ser:%06lX\r\n"
                "Cnt:%04lX\r\n"
                "CRC:%02X\r\n"
                "Type:%02X\r\n"
                "Sd:%06lX",
                instance->base.protocol->name,
                128,
                instance->key1_high,
                instance->key1_low,
                key2_value,
                instance->decrypted_button,
                instance->decrypted_serial,
                (uint32_t)instance->decrypted_counter,
                instance->decrypted_crc,
                instance->decrypted_type,
                instance->decrypted_seed);
        } else if(instance->decrypted_type == 0x36) {
            furi_string_printf(
                output,
                "%s %dbit\r\n"
                "Key1:%08lX%08lX\r\n"
                "Key2:%04X\r\n"
                "Btn:%02X\r\n"
                "Ser:%06lX\r\n"
                "Cnt:%08lX\r\n"
                "CRC:%02X\r\n"
                "Type:%02X\r\n"
                "Sd:%06lX",
                instance->base.protocol->name,
                128,
                instance->key1_high,
                instance->key1_low,
                key2_value,
                instance->decrypted_button,
                instance->decrypted_serial,
                instance->decrypted_counter,
                instance->decrypted_crc,
                instance->decrypted_type,
                instance->decrypted_seed);
        } else {
            furi_string_printf(
                output,
                "%s %dbit\r\n"
                "Key1:%08lX%08lX\r\n"
                "Key2:%X",
                instance->base.protocol->name,
                128,
                instance->key1_high,
                instance->key1_low,
                key2_value);
        }
    } else {
        furi_string_printf(
            output,
            "%s %dbit\r\n"
            "Key1:%08lX%08lX\r\n"
            "Key2:%X",
            instance->base.protocol->name,
            128,
            instance->key1_high,
            instance->key1_low,
            key2_value);
    }
}
