#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "hardware/gpio.h"
#include <string.h>  // Inclui a biblioteca padrão de manipulação de strings para funções como snprintf.
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/dns.h"

#define LED_G_PIN 11
#define LED_B_PIN 12
#define LED_R_PIN 13
#define BTN_A_PIN 5
#define BTN_B_PIN 6

#define TCP_SERVER "tcpbin.com"
#define TCP_PORT 4242


// Definindo pinos e configurações de hardware
const uint8_t pir_pin = 15;  // Define o pino GPIO 15 como o pino de entrada para o sensor PIR.
// Estado do Sensor
int estado_sensor = 0;
int estado_botaoa = 0;
int estado_botaob = 0;
char *message;
// Variável para armazenar o último estado do sensor PIR
bool last_motion_state = false;  // Armazena o último estado do sensor PIR (movimento detectado ou não).

void set_leds(bool green, bool blue, bool red) {
  gpio_put(LED_G_PIN, green);
  gpio_put(LED_B_PIN, blue);
  gpio_put(LED_R_PIN, red);
}

void inicia_leds() {
  // Inicializa os pinos dos LEDs e configura como saída
  gpio_init(LED_G_PIN);
  gpio_set_dir(LED_G_PIN, GPIO_OUT);
  gpio_init(LED_B_PIN);
  gpio_set_dir(LED_B_PIN, GPIO_OUT);
  gpio_init(LED_R_PIN);
  gpio_set_dir(LED_R_PIN, GPIO_OUT);
}

void inicia_botoes() {
  // Inicializa os pinos dos botões e configura como entrada com pull-up
  gpio_init(BTN_A_PIN);
  gpio_set_dir(BTN_A_PIN, GPIO_IN);
  gpio_pull_down(BTN_A_PIN);
  gpio_init(BTN_B_PIN);
  gpio_set_dir(BTN_B_PIN, GPIO_IN);
  gpio_pull_down(BTN_B_PIN);
}

static struct tcp_pcb *tcp_client_pcb;

// Callback for when data is received
err_t tcp_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
  if (p == NULL) {
    printf("Connection closed by server.\n");
    tcp_close(tpcb);
    return ERR_OK;
  }

  // char buffer[128];
  char buffer[2048];
  pbuf_copy_partial(p, buffer, p->len, 0);
  buffer[p->len] = '\0';
  printf("Received: %s\n", buffer);

  pbuf_free(p);
  return ERR_OK;
}

// Callback for when the connection is established
err_t tcp_connect_callback(void *arg, struct tcp_pcb *tpcb, err_t err) {
  if (err != ERR_OK) {
    printf("Failed to connect to server.\n");
    return err;
  }

  printf("Connected to server.\n");
  if (estado_sensor >= 1) {
    message = "Movimento detectado! Alerta ativado.\n";
    tcp_write(tpcb, message, strlen(message), TCP_WRITE_FLAG_COPY);

    tcp_recv(tpcb, tcp_recv_callback);
  } else {
    if (estado_sensor <= 0) {
      message = "Sem movimento. Alerta desativado.\n";
      tcp_write(tpcb, message, strlen(message), TCP_WRITE_FLAG_COPY);

      tcp_recv(tpcb, tcp_recv_callback);
    }
  }


  if (estado_botaoa >= 1) {
    message = "O status do Botao A foi ativado (1).\n";
  } else {
    message = "O status do Botao A foi desativado (0).\n";
  }

  tcp_write(tpcb, message, strlen(message), TCP_WRITE_FLAG_COPY);

  tcp_recv(tpcb, tcp_recv_callback);
  estado_botaoa = 0;
  if (estado_botaob >= 1) {
    message = "O status do Botao B foi ativado (1).\n";
  } else {
    message = "O status do Botao B foi desativado (0).\n";
  }

  tcp_write(tpcb, message, strlen(message), TCP_WRITE_FLAG_COPY);

  tcp_recv(tpcb, tcp_recv_callback);
  estado_botaob = 0;
  return ERR_OK;
}

// DNS callback function
static void dns_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
  if (ipaddr == NULL) {
    printf("Failed to resolve DNS for %s\n", name);
    return;
  }

  printf("Resolved %s to %s\n", name, ipaddr_ntoa(ipaddr));
  tcp_connect(tcp_client_pcb, ipaddr, TCP_PORT, tcp_connect_callback);
}


void print_network_info() {
  struct netif *netif = netif_list;
  printf("Network interface: %c%c\n", netif->name[0], netif->name[1]);
  printf("IP Address: %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
  printf("Netmask: %s\n", ip4addr_ntoa(netif_ip4_netmask(netif)));
  printf("Gateway: %s\n", ip4addr_ntoa(netif_ip4_gw(netif)));
}

void connect_to_server() {
  tcp_client_pcb = tcp_new();
  if (!tcp_client_pcb) {
    printf("Failed to create TCP PCB.\n");
    return;
  }

  printf("Resolving %s...\n", TCP_SERVER);
  ip_addr_t server_ip;
  err_t err = dns_gethostbyname(TCP_SERVER, &server_ip, dns_callback, NULL);
  if (err == ERR_OK) {
    printf("DNS resolved immediately: %s\n", ipaddr_ntoa(&server_ip));
    tcp_connect(tcp_client_pcb, &server_ip, TCP_PORT, tcp_connect_callback);
  } else if (err != ERR_INPROGRESS) {
    printf("DNS resolution failed: %d\n", err);
    tcp_close(tcp_client_pcb);
  }
}


void conectar_wifi() {
  if (cyw43_arch_init()) {  // Inicializa o hardware Wi-Fi.
    printf("Erro ao inicializar o Wi-Fi.\n");  // Se falhar, imprime uma mensagem de erro.
    conectar_wifi();  // Retorna 1 para indicar erro.
  }
  cyw43_arch_enable_sta_mode();  // Habilita o modo estação (STA) para conectar-se a uma rede Wi-Fi.

  // Conecta ao Wi-Fi
  const char *ssid = "Wokwi-GUEST";  // Define o nome da rede Wi-Fi.
  const char *password = "";  // Define a senha da rede Wi-Fi.
  printf("Conectando ao Wi-Fi...\n");  // Imprime uma mensagem indicando que está tentando conectar ao Wi-Fi.
  if (cyw43_arch_wifi_connect_timeout_ms(ssid, password, CYW43_AUTH_WPA2_AES_PSK, 10000)) {  // Tenta conectar ao Wi-Fi.
    printf("Erro ao conectar ao Wi-Fi.\n");  // Se falhar, imprime uma mensagem de erro.
    conectar_wifi();  // Retorna 1 para indicar erro.
  }
  printf("Conectado ao Wi-Fi.\n");  // Imprime uma mensagem indicando que a conexão foi bem-sucedida.

}
void botoes(void) {
  while (true) {

    if (gpio_get(BTN_A_PIN) && gpio_get(BTN_B_PIN)) {
      set_leds(1, 1, 1);  // Acende todos os LEDs
      estado_botaoa = 1;
      estado_botaob = 1;
      break;
    } else if (gpio_get(BTN_A_PIN)) {
      set_leds(1, 0, 0);  // Acende apenas o LED verde
      estado_botaoa = 1;
      break;
    } else if (gpio_get(BTN_B_PIN)) {
      set_leds(0, 1, 0);  // Acende apenas o LED azul
      estado_botaob = 1;
      break;
    } else {
      set_leds(0, 0, 1);  // Acende apenas o LED vermelho
      //   estado_botaoa = 0;
      //   estado_botaob = 0;
      break;
    }
    sleep_ms(100);
    //return;
  }
}
int main() {
  //printf("Vou inicializar o Wi-Fi.\n");
  // Inicializa a comunicação serial
  stdio_init_all();  // Inicializa a comunicação serial para permitir a saída de texto via USB.
  /*
    // Inicializa o Wi-Fi (para o Raspberry Pi Pico W)
    if (cyw43_arch_init()) {  // Inicializa o hardware Wi-Fi.
     printf("Erro ao inicializar o Wi-Fi.\n");  // Se falhar, imprime uma mensagem de erro.
     return 1;  // Retorna 1 para indicar erro.
    }
    cyw43_arch_enable_sta_mode();  // Habilita o modo estação (STA) para conectar-se a uma rede Wi-Fi.

    // Conecta ao Wi-Fi
    const char *ssid = "SUA_REDE_WIFI";  // Define o nome da rede Wi-Fi.
    const char *password = "SUA_SENHA_WIFI";  // Define a senha da rede Wi-Fi.
    printf("Conectando ao Wi-Fi...\n");  // Imprime uma mensagem indicando que está tentando conectar ao Wi-Fi.
    if (cyw43_arch_wifi_connect_timeout_ms(ssid, password, CYW43_AUTH_WPA2_AES_PSK, 10000)) {  // Tenta conectar ao Wi-Fi.
     printf("Erro ao conectar ao Wi-Fi.\n");  // Se falhar, imprime uma mensagem de erro.
     return 1;  // Retorna 1 para indicar erro.
    }
    printf("Conectado ao Wi-Fi.\n");  // Imprime uma mensagem indicando que a conexão foi bem-sucedida.
  */

  inicia_leds();
  inicia_botoes();
  conectar_wifi();
  print_network_info();
  // Configura os pinos
  gpio_init(pir_pin);  // Inicializa o pino do sensor PIR.
  gpio_set_dir(pir_pin, GPIO_IN);  // Configura o pino do sensor PIR como entrada.

  printf("Sistema iniciado.\n");  // Imprime uma mensagem indicando que o sistema foi iniciado.

  //botoes();
  while (true) {  // Loop infinito para monitorar continuamente o sensor PIR.
    bool current_motion_state = gpio_get(pir_pin);  // Lê o estado atual do sensor PIR.

    if (current_motion_state != last_motion_state) {  // Verifica se o estado do sensor mudou.
      if (current_motion_state) {  // Se o movimento for detectado.
       // printf("Movimento detectado! Alerta ativado.\n");  // Imprime uma mensagem.
        estado_sensor = 1;
      //  printf("O estado do sensor eh = %d\n", estado_sensor);
        connect_to_server();
      } else {  // Se o movimento cessar.
        // printf("Sem movimento. Alerta desativado.\n");  // Imprime uma mensagem.
        // estado_sensor = 0;
        //  printf("O estado do sensor eh = %d\n", estado_sensor);
        //  connect_to_server();
      }
      //  printf("O estado do botao A  eh = %d\n", estado_botaoa);
      //    printf("O estado do botao B  eh = %d\n", estado_botaob);
      //   estado_botaoa = 0;
      //   estado_botaob = 0;
      last_motion_state = current_motion_state;  // Atualiza o último estado do sensor.
    }

    // Se o movimento persistir, mantenha o LED ligado e toque o buzzer em intervalos
    if (current_motion_state) {  // Se o movimento for detectado.
      //sleep_ms(600);  // Aguarda 600ms antes de tocar novamente.
    }
    botoes();
    sleep_ms(1000);  // Aguarda 100ms antes de verificar novamente o estado do sensor.
  }

  return 0;  // Retorna 0 (nunca será alcançado devido ao loop infinito).
}
$abcdeabcde151015202530fghijfghij