#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "esp_mesh.h"
#include "esp_err.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "esp_mesh_internal.h"
#include "lwip/ip_addr.h"
#include <string.h>
#include "driver/ledc.h"

#include "esp_netif.h"


static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77};

esp_err_t event_handler(void *ctx, system_event_t *event){
    return ESP_OK;
}

void app_main(void){
	/*  tcpip initialization */
	tcpip_adapter_init();
	/*
	 * for mesh
	 * stop DHCP server on softAP interface by default
	 * stop DHCP client on station interface by default
	 */
	ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
	ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));

	/*  event initialization */
	ESP_ERROR_CHECK(esp_event_loop_create_default());

	/*  Wi-Fi initialization */
	wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&config));
	/*  register IP events handler */
	ESP_ERROR_CHECK(esp_event_handler_register("ip", IP_EVENT_STA_GOT_IP, &event_handler, NULL));
	ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
	ESP_ERROR_CHECK(esp_wifi_start());

	/*  mesh initialization */
	ESP_ERROR_CHECK(esp_mesh_init());
	/*  register mesh events handler */
	ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

	/* Enable the Mesh IE encryption by default */
	mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
	/* mesh ID */
	memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
	/* channel (must match the router's channel) */
	cfg.channel = CONFIG_MESH_CHANNEL;
	/* router */
	cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID);
	memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len);
	memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD,
	       strlen(CONFIG_MESH_ROUTER_PASSWD));
	/* mesh softAP */
	cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS;
	memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD,
	       strlen(CONFIG_MESH_AP_PASSWD));
	ESP_ERROR_CHECK(esp_mesh_set_config(&cfg));

	/* mesh start */
	ESP_ERROR_CHECK(esp_mesh_start());



	//Disable self organized networking
	esp_mesh_set_self_organized(0, 0);

	//Stop any scans already in progress
	esp_wifi_scan_stop();
	//Manually start scan. Will automatically stop when run to completion
	wifi_scan_config_t scanConf = {
        .ssid = NULL,
        .bssid = NULL,
        .channel = 0,
        .show_hidden = false
    };
    ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, true));

	//Process scan results

	//Re-enable self organized networking if still connected
	esp_mesh_set_self_organized(1, 0);

	//Re-enable self organized networking if non-root and disconnected
	esp_mesh_set_self_organized(1, 1);

	//Re-enable self organized networking if root and disconnected
	esp_mesh_set_self_organized(1, 0);  //Don't select new parent
	esp_mesh_connect();                 //Manually reconnect to router
}
