#include "main.h"


#include "esp_at.h"
#include "wifi_portal.h"
#include <string.h>
#include <stdio.h>
#include <stdbool.h>

#define ESP_RX_BUF_SIZE 1024

static char esp_rx_buf[ESP_RX_BUF_SIZE];
static volatile uint16_t esp_rx_idx = 0;


extern UART_HandleTypeDef huart1; // ESP
extern UART_HandleTypeDef huart3; // DEBUG
/*************************************************/

static void dbg(const char *s)
{
    HAL_UART_Transmit(&huart3, (uint8_t *)s, strlen(s), HAL_MAX_DELAY);
}

/*************************************************/

void ESP_RxByte(uint8_t byte)
{
    if (esp_rx_idx < ESP_RX_BUF_SIZE - 1)
    {
        esp_rx_buf[esp_rx_idx++] = byte;
        esp_rx_buf[esp_rx_idx] = 0;
    }
}

/*************************************************/

char* ESP_GetBuffer(void)
{
    return esp_rx_buf;
}
/*************************************************/

void ESP_ClearBuffer(void)
{
    esp_rx_idx = 0;
    esp_rx_buf[0] = 0;
}

/*************************************************/
static bool ESP_WaitFor(const char *expect, uint32_t timeout)
{
    uint32_t start = HAL_GetTick();

    while ((HAL_GetTick() - start) < timeout)
    {
        if (strstr(esp_rx_buf, expect))
            return true;

        if (strstr(esp_rx_buf, "ERROR"))
            return false;

        if (strstr(esp_rx_buf, "busy"))
        {
            HAL_Delay(100);
            ESP_ClearBuffer();
            start = HAL_GetTick();
        }

        HAL_Delay(1);
    }

    return false;
}

/*************************************************/

bool ESP_SendCmd(const char *cmd, const char *expect, uint32_t timeout)
{
	ESP_ClearBuffer();

    HAL_UART_Transmit(&huart1, (uint8_t *)cmd, strlen(cmd), HAL_MAX_DELAY);
    HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, HAL_MAX_DELAY);

    dbg(">> ");
    dbg(cmd);
    dbg("\r\n");

    bool ok = ESP_WaitFor(expect, timeout);

    dbg("<< ");
    dbg(esp_rx_buf);
    dbg("\r\n");
    HAL_Delay(50);  // 🔥 estabiliza ESP
    return ok;
}

/*************************************************/

bool ESP_EnableMultiConn(void)
{
    return ESP_SendCmd("AT+CIPMUX=1", "OK", 3000);
}

bool ESP_StartSoftAP(const char *ssid, const char *pass)
{
    char cmd[160];

    if (!ESP_SendCmd("AT+CWMODE=2", "OK", 3000))
        return false;

    snprintf(cmd, sizeof(cmd),
             "AT+CWSAP=\"%s\",\"%s\",1,3,4",
             ssid, pass);

    return ESP_SendCmd(cmd, "OK", 5000);
}

bool ESP_StartServer(uint16_t port)
{
    char cmd[64];
    snprintf(cmd, sizeof(cmd), "AT+CIPSERVER=1,%u", port);
    return ESP_SendCmd(cmd, "OK", 5000);
}

/*************************************************/

bool ESP_SendLinkData(int link_id, const char *data)
{
    char cmd[64];
    size_t len = strlen(data);

    ESP_ClearBuffer();

    snprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d,%u", link_id, (unsigned)len);

    HAL_UART_Transmit(&huart1, (uint8_t *)cmd, strlen(cmd), HAL_MAX_DELAY);
    HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, HAL_MAX_DELAY);

    if (!ESP_WaitFor(">", 3000))
        return false;

    HAL_UART_Transmit(&huart1, (uint8_t *)data, len, HAL_MAX_DELAY);

    return ESP_WaitFor("SEND OK", 5000);
}

int ESP_HasIPD(void)
{
    if (strstr(ESP_GetBuffer(), "+IPD"))
        return 1;

    return 0;
}


void ESP_SendData(const char *data)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)data, strlen(data), 2000);
}
/*************************************************/

bool ESP_CloseLink(int link_id)
{
    char cmd[32];
    snprintf(cmd, sizeof(cmd), "AT+CIPCLOSE=%d", link_id);
    return ESP_SendCmd(cmd, "OK", 3000);
}

/*************************************************/
void ESP_Init(void)
{
    // 🔥 manda reset à bruta
    ESP_SendData("AT+RST\r\n");

    dbg("RESET ESP...\r\n");

    // 🔥 espera real (não confies no WaitFor)
    HAL_Delay(6000);

    ESP_ClearBuffer();

    dbg("ESP PRONTO\r\n");

    // 🔥 agora sim começa
    if (!ESP_SendCmd("AT", "OK", 3000))
        dbg("AT FAIL\r\n");

    if (!ESP_SendCmd("ATE0", "OK", 3000))
        dbg("ATE0 FAIL\r\n");

    if (!ESP_SendCmd("AT+CIPDINFO=1", "OK", 3000))
        dbg("CIPDINFO FAIL\r\n");

    if (!ESP_SendCmd("AT+CWMODE=2", "OK", 3000))
        dbg("CWMODE FAIL\r\n");

    if (!ESP_SendCmd("AT+CWSAP=\"STM32\",\"12345678\",1,3,4", "OK", 8000))
        dbg("CWSAP FAIL\r\n");

    HAL_Delay(3000);

    if (!ESP_SendCmd("AT+CIPMUX=1", "OK", 3000))
        dbg("CIPMUX FAIL\r\n");

    if (!ESP_SendCmd("AT+CIPSERVER=1,80", "OK", 5000))
        dbg("CIPSERVER FAIL\r\n");
}

/*************************************************/
__attribute__((unused))
static int parse_ipd_link(const char *p)
{
    int link = -1;
    sscanf(p, "+IPD,%d,", &link);
    return link;
}

/*************************************************/
void ESP_Task(void)
{
    char *buf = ESP_GetBuffer();

    if (!strstr(buf, "GET "))
        return;

    dbg("HTTP DETECTADO\r\n");

    // 🔥 ESPERAR O RESTO DO HTTP CHEGAR
    HAL_Delay(200);

    int link_id = 0;

    const char *resp =
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/html\r\n"
        "Connection: close\r\n"
        "\r\n"
        "<h1>PORTAL XUPA FUNCIONA</h1>";

    char cmd[64];

    snprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d,%u",
             link_id, (unsigned)strlen(resp));

    if (ESP_SendCmd(cmd, ">", 3000))
    {
        ESP_SendData(resp);
        ESP_WaitFor("SEND OK", 5000);
    }

    snprintf(cmd, sizeof(cmd), "AT+CIPCLOSE=%d", link_id);
    ESP_SendCmd(cmd, "OK", 3000);

    ESP_ClearBuffer();
}
