#include "stm32c0xx_hal.h"
#include <stdlib.h>
#include <stdbool.h>

UART_HandleTypeDef huart2;

// Настройка `_write` для использования `printf`
int _write(int file, char *ptr, int len) {
    HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, HAL_MAX_DELAY);
    return len;
}

// Константы
#define LED_COUNT 2
#define BUTTON_COUNT 2

// Пины для светодиодов
const uint16_t LED_Pins[LED_COUNT] = { GPIO_PIN_5, GPIO_PIN_6 }; // PA5, PA6
#define LED_GPIO_Port GPIOA

// Пины для кнопок
const uint16_t Button_Pins[BUTTON_COUNT] = { GPIO_PIN_0, GPIO_PIN_1 }; // PB0, PB1
#define Button_GPIO_Port GPIOB

// Игровые состояния
typedef enum {
    GAME_INIT,
    GAME_SHOW_SEQUENCE,
    GAME_PLAYER_INPUT,
    GAME_CHECK_RESULT,
    GAME_OVER
} GameState;

// Переменные
GameState currentState = GAME_INIT;
uint8_t sequence[10]; // Последовательность светодиодов
uint8_t sequenceLength = 0; // Текущая длина последовательности
uint8_t playerIndex = 0;

// Прототипы функций
void GenerateSequence(void);
void ShowSequence(void);
uint8_t GetButtonInput(void);
void SetAllLEDs(uint8_t state);
void LightLED(uint8_t ledIndex);
void MX_GPIO_Init(void);
void MX_USART2_UART_Init(void);

// Основной цикл
int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART2_UART_Init();

    printf("Starting the game...\r\n");

    while (1) {
        switch (currentState) {
            case GAME_INIT:
                sequenceLength = 1; // Начальная длина последовательности
                GenerateSequence();
                printf("Game initialized. Sequence length: %d\r\n", sequenceLength);
                currentState = GAME_SHOW_SEQUENCE;
                break;

            case GAME_SHOW_SEQUENCE:
                printf("Showing sequence...\r\n");
                ShowSequence();
                playerIndex = 0;
                currentState = GAME_PLAYER_INPUT;
                break;

            case GAME_PLAYER_INPUT:
            {
                printf("Waiting for player input. Player index = %d\r\n", playerIndex);
                uint8_t input = GetButtonInput();
                if (input != 0xFF) { // Если есть нажатие
                    printf("Button pressed: %d\r\n", input);
                    if (input == sequence[playerIndex]) {
                        playerIndex++;
                        printf("Correct! Player index = %d, sequenceLength = %d\r\n", playerIndex, sequenceLength);
                        if (playerIndex == sequenceLength) {
                            sequenceLength++;
                            currentState = GAME_CHECK_RESULT;
                        }
                    } else {
                        printf("Incorrect button! Expected: %d, got: %d\r\n", sequence[playerIndex], input);
                        currentState = GAME_OVER;
                    }
                }
                break;
            }

            case GAME_CHECK_RESULT:
                printf("Checking result...\r\n");
                if (sequenceLength > sizeof(sequence)) {
                    printf("Player wins! Sequence completed.\r\n");
                    currentState = GAME_OVER;
                } else {
                    HAL_Delay(1000); // Короткая пауза перед следующей последовательностью
                    currentState = GAME_SHOW_SEQUENCE;
                }
                break;

            case GAME_OVER:
                printf("Game Over. Restarting...\r\n");
                SetAllLEDs(1); // Все светодиоды горят 2 секунды
                HAL_Delay(2000);
                SetAllLEDs(0);
                currentState = GAME_INIT;
                break;
        }
    }
}

// Генерация последовательности
void GenerateSequence(void) {
    for (uint8_t i = 0; i < sizeof(sequence); i++) {
        sequence[i] = rand() % LED_COUNT;
    }
}

// Показ последовательности
void ShowSequence(void) {
    for (uint8_t i = 0; i < sequenceLength; i++) {
        LightLED(sequence[i]);
        HAL_Delay(500);
        SetAllLEDs(0);
        HAL_Delay(200);
    }
}

// Получение нажатия кнопки
uint8_t GetButtonInput(void) {
    for (uint8_t i = 0; i < BUTTON_COUNT; i++) {
        if (HAL_GPIO_ReadPin(Button_GPIO_Port, Button_Pins[i]) == GPIO_PIN_SET) {
            while (HAL_GPIO_ReadPin(Button_GPIO_Port, Button_Pins[i]) == GPIO_PIN_SET); // Ждем отпускания
            return i;
        }
    }
    return 0xFF; // Нет нажатия
}

// Управление светодиодами
void SetAllLEDs(uint8_t state) {
    for (uint8_t i = 0; i < LED_COUNT; i++) {
        HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pins[i], state ? GPIO_PIN_SET : GPIO_PIN_RESET);
    }
}

void LightLED(uint8_t ledIndex) {
    SetAllLEDs(0);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pins[ledIndex], GPIO_PIN_SET);
}

// Инициализация GPIO
void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // Настройка светодиодов
    GPIO_InitStruct.Pin = LED_Pins[0] | LED_Pins[1];
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);

    // Настройка кнопок
    GPIO_InitStruct.Pin = Button_Pins[0] | Button_Pins[1];
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(Button_GPIO_Port, &GPIO_InitStruct);
}

// Настройка UART
void MX_USART2_UART_Init(void) {
    huart2.Instance = USART2;
    huart2.Init.BaudRate = 115200;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;

    if (HAL_UART_Init(&huart2) != HAL_OK) {
        printf("UART initialization failed\r\n");
    }
}

// Настройка системных часов
void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}