#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi_types.h"
#include "esp_err.h"
#include "esp_wifi_types.h"
#include "lwip/err.h"
#include "lwip/sys.h"

#include "esp_http_client.h"
#include "esp_tls.h"
#include "esp_crt_bundle.h"

#define EXAMPLE_ESP_WIFI_SSID      "ssid"
#define EXAMPLE_ESP_WIFI_PASS      "pass"

#define THINGSPEAK_API_KEY "XXXXXXXXXXXXXXXX"//write API key
#define THINGSPEAK_CHANNEL_ID "XXXXXXX" // channel ID
#define MAX_HTTP_OUTPUT_BUFFER 2048


static EventGroupHandle_t s_wifi_event_group;


int data_arr[4]={29,54,61,11};

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG1 = "wifi station";
static const char *TAG2 = "HTTP_CLIENT";
static const char *TAG3 = "info";


static int s_retry_num = 0;

esp_err_t http_event_handler(esp_http_client_event_t *evt) {
    static char *output_buffer;
    static int output_len;
    
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGE(TAG2, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGI(TAG2, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGI(TAG2, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGI(TAG2, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGI(TAG2, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);

           
            

            break;

        case HTTP_EVENT_ON_FINISH:
            ESP_LOGI(TAG2, "HTTP_EVENT_ON_FINISH");

              if (output_buffer != NULL) {
                // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
                ESP_LOG_BUFFER_HEX(TAG2, output_buffer, output_len);
                free(output_buffer);
                output_buffer = NULL;
            }
            output_len = 0;
            
            break;

        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG2, "HTTP_EVENT_DISCONNECTED");

          
            break;

        case HTTP_EVENT_REDIRECT:
            ESP_LOGI(TAG2, "HTTP_EVENT_REDIRECT");
            break;
    }
    return ESP_OK;
}

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{

    

    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        
        ESP_ERROR_CHECK(esp_wifi_connect());
       
        ESP_LOGI(TAG1,"initial wifi connecting...");
        } 
        //------------------------------------------------
        else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < 7) {
            ESP_ERROR_CHECK(esp_wifi_connect());
         
            s_retry_num++;
            ESP_LOGI(TAG1, "retry to connect to the AP");
        } 
        else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG1,"connect to the AP fail");
    }

     else if(event_base==WIFI_EVENT && event_id==WIFI_EVENT_STA_CONNECTED){

        ESP_LOGI(TAG1,"WIFI_EVENT_STA_CONNECTED");
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
        s_retry_num=0;
     } 


}

static void http_rest_with_url(int var1, int var2){
   
    char data[50];
    sprintf(data, "api_key=%s&field1=%d", THINGSPEAK_API_KEY, var1);
    char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER]={0};

    //sukonfiguruojami http kliento parametrai
      esp_http_client_config_t config = {
        .url = "https://api.thingspeak.com/update?data",
        .method=HTTP_METHOD_POST,
        .event_handler = http_event_handler,
        .user_data = local_response_buffer,        // Pass address of local buffer to get response
        .transport_type = HTTP_TRANSPORT_OVER_SSL,  //Specify transport type
        .crt_bundle_attach = esp_crt_bundle_attach, //Attach the certificate bundle
        .disable_auto_redirect = true,
    };

     esp_http_client_handle_t client = esp_http_client_init(&config);
     
    ESP_LOGI(TAG2,"http client initialized");
     

    //setting http header
    esp_err_t err_set_header=esp_http_client_set_header(client, "application/x-www-form-urlencoded", "application/json");
    if(err_set_header==ESP_OK){ESP_LOGI(TAG2,"header set");}
    else {ESP_LOGI(TAG2,"failed to set header: %s", esp_err_to_name(err_set_header));}

    esp_err_t err_set_method=esp_http_client_set_method(client, HTTP_METHOD_POST);
    if(err_set_method==ESP_OK){ESP_LOGI(TAG2,"method set for field1");}
    else {ESP_LOGI(TAG2,"failed to set method for field1: %s", esp_err_to_name(err_set_method));}

    esp_err_t err_set_post_field=esp_http_client_set_post_field(client, data, strlen(data));
    if(err_set_post_field==ESP_OK){ESP_LOGI(TAG2,"post field1 set");}
    else {ESP_LOGI(TAG2,"failed to set post field1: %s", esp_err_to_name(err_set_post_field));}

    //ESP_LOGI(TAG3,"printing out data variable %s",data);

    esp_err_t err = esp_http_client_perform(client);
    if(err==ESP_OK){
        ESP_LOGI(TAG2,"HTTP Post Status = %d , content_length=%lld",esp_http_client_get_status_code(client),esp_http_client_get_content_length(client));
    }
    else {
        ESP_LOGE(TAG2,"HTTP POST request failed: %s", esp_err_to_name(err));
    }
//--------------------------new http request----------------------------
    char data2[50];
    sprintf(data2, "api_key=%s&field5=%d", THINGSPEAK_API_KEY, var2);

    //setting URL
    esp_err_t err_set_url2=esp_http_client_set_url(client, "https://api.thingspeak.com/update?data2");
    if(err_set_url2==ESP_OK){ESP_LOGI(TAG2,"url2 set");}
    else {ESP_LOGI(TAG2,"failed to set url2: %s", esp_err_to_name(err_set_url2));}

    //setting method
    esp_err_t err_set_method2=esp_http_client_set_method(client, HTTP_METHOD_POST);
    if(err_set_method2==ESP_OK){ESP_LOGI(TAG2,"method set for field5");}
    else {ESP_LOGI(TAG2,"failed to set method for field5: %s", esp_err_to_name(err_set_method2));}

    //setting header
    esp_err_t err_set_header2=esp_http_client_set_header(client, "application/x-www-form-urlencoded", "application/json");
    if(err_set_header2==ESP_OK){ESP_LOGI(TAG2,"header2 set");}
    else {ESP_LOGI(TAG2,"failed to set header2: %s", esp_err_to_name(err_set_header2));}

    //setting post field
    esp_err_t err_set_post_field2=esp_http_client_set_post_field(client, data2, strlen(data2));
    if(err_set_post_field2==ESP_OK){ESP_LOGI(TAG2,"post field5 set");}
    else {ESP_LOGI(TAG2,"failed to set post field5: %s", esp_err_to_name(err_set_post_field2));}

    //ESP_LOGI(TAG3,"printing out data variable %s",data2);

    //performing request
    esp_err_t err2 = esp_http_client_perform(client);
    if(err2==ESP_OK){
        ESP_LOGI(TAG2,"HTTP Post Status = %d , content_length=%lld",esp_http_client_get_status_code(client),esp_http_client_get_content_length(client));
    }
    else {
        ESP_LOGE(TAG2,"HTTP POST request failed: %s", esp_err_to_name(err2));
    }

    //------------------------cleanup
    esp_http_client_cleanup(client);
    
    ESP_LOGI(TAG2,"HTTP client operation ended");
   

//wifi disconnect phase--------------------------------------------------
    esp_err_t err_wifi_disconnect=esp_wifi_disconnect();
    if(err_wifi_disconnect==ESP_OK){ESP_LOGI(TAG1,"Disconnected from wifi");}
    else {ESP_LOGI(TAG1,"failed to disconnect from wifi: %s", esp_err_to_name(err_wifi_disconnect));}

     esp_err_t err_wifi_stop=esp_wifi_stop();
    if(err_wifi_stop==ESP_OK){ESP_LOGI(TAG1,"Stopped wifi driver");}
    else {ESP_LOGI(TAG1,"failed to stop wifi driver: %s", esp_err_to_name(err_wifi_stop));}

     esp_err_t err_wifi_deinit=esp_wifi_deinit();
    if(err_wifi_deinit==ESP_OK){ESP_LOGI(TAG1,"Deinitialized wifi");}
    else {ESP_LOGI(TAG1,"failed to deinitialize wifi: %s", esp_err_to_name(err_wifi_deinit));}

    ESP_LOGI(TAG3,"Application ended");

}



void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
   
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .scan_method=WIFI_ALL_CHANNEL_SCAN,
            .sort_method=WIFI_CONNECT_AP_BY_SIGNAL,
           
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
   
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start());
    ESP_LOGI(TAG1, "wifi_init_sta finished.");
    ESP_ERROR_CHECK(esp_wifi_scan_start(NULL,true));


 
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);


    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG1, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
                 ESP_LOGI(TAG1,"Connected to wifi, calling http post after 4 s delay");
                 vTaskDelay(4000 / portTICK_PERIOD_MS);
                 http_rest_with_url(data_arr[0],data_arr[1]);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG1, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG1, "UNEXPECTED EVENT");
    }


}




void app_main(void)
{


    esp_err_t ret = nvs_flash_init();
  
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());

      ret = nvs_flash_init();
 
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG1, "ESP_WIFI_MODE_STA");
    wifi_init_sta();

}