#include "webinterface.h"

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <WiFiAP.h>
#include <ESPmDNS.h>
#include <Update.h>
#include "parameters.h"
#include "romfs.h"
#include "check_firmware.h"
#include "status.h"

static WebServer server(80); // 80 是 HTTP 协议的默认端口
static bool front_16byte_flag = false; // 调试观察前16个字节使用
/*
  serve files from ROMFS
  ROMFS_Handler 是 Web 服务器的 “静态资源处理器”：拦截所有 Web 请求，
  将 URI 映射到 ROMFS 中的 web/ 目录下的文件（如 / → web/index.html），
  判断文件是否存在并匹配正确的 Content-Type，最终把 ROMFS 中的文件流式返回给浏览器，
  是 Web 升级页面能正常加载的关键
 */
class ROMFS_Handler : public RequestHandler
{
    bool canHandle(HTTPMethod method, String uri) {
        if (uri == "/") {
            uri = "/index.html";
        }
        uri = "web" + uri;
        if (ROMFS::exists(uri.c_str())) {
            return true;
        }
        return false;
    }

    bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) {
        if (requestUri == "/") {
            requestUri = "/index.html";
        }
        String uri = "web" + requestUri;
        Serial.printf("handle: '%s'\n", requestUri.c_str());

        // work out content type
        const char *content_type = "text/html";
        const struct {
            const char *extension;
            const char *content_type;
        } extensions[] = {
            { ".js", "text/javascript" },
            { ".jpg", "image/jpeg" },
            { ".png", "image/png" },
            { ".css", "text/css" },
        };
        for (const auto &e : extensions) {
            if (uri.endsWith(e.extension)) {
                content_type = e.content_type;
                break;
            }
        }

        auto *f = ROMFS::find_stream(uri.c_str());
        if (f != nullptr) {
            server.sendHeader("Content-Encoding", "gzip");
            server.streamFile(*f, content_type);
            delete f;
            return true;
        }
        return false;
    }

} ROMFS_Handler;

/*
  serve files from ROMFS
 */
class AJAX_Handler : public RequestHandler
{
    bool canHandle(HTTPMethod method, String uri) {
        return uri == "/ajax/status.json";
    }

    bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) {
        if (requestUri != "/ajax/status.json") {
            return false;
        }
        server.send(200, "application/json", status_json());
        return true;
    }

} AJAX_Handler;

/*
  init web server
  该函数是 Web 升级的 “总开关”：启动 WiFi AP 并初始化 Web 服务器，
  注册 AJAX/ROMFS 处理器支撑页面显示，绑定 /update 接口处理固件上传，
  上传过程中缓存固件头部、写入 OTA 分区，最后通过你之前关注的 check_OTA_next() 校验固件合法性，
  合法则升级重启，非法则返回失败，是 Web 升级从 “页面访问” 到 “固件生效” 的全流程入口
 */
void WebInterface::init(void)
{
    Serial.printf("WAP start %s %s\n", g.wifi_ssid, g.wifi_password);
    IPAddress myIP = WiFi.softAPIP();  // 获取 AP 模式默认 IP（192.168.4.1）

    server.addHandler( &AJAX_Handler ); // 处理 AJAX 异步请求（如获取模块状态）
    server.addHandler( &ROMFS_Handler ); // 处理静态页面（HTML/CSS/JS）

    /*handling uploading firmware file */
    server.on("/update", HTTP_POST, []() {
        if (Update.hasError()) {
			server.sendHeader("Connection", "close");
		    server.send(500, "text/plain","FAIL");
		    Serial.printf("Update Failed: Update function has errors\n");
		    delay(5000);
		} else {
			server.sendHeader("Connection", "close");
			server.send(200, "text/plain","OK");
			Serial.printf("Update Success: \nRebooting...\n");
			delay(1000);
			ESP.restart();
		}
    }, [this]() { // 回调 2：上传过程中处理固件数据（核心中的核心）
        HTTPUpload& upload = server.upload(); 
        // 获取待写入的备用 OTA 分区（OTA0/OTA1 中非当前运行的分区）
        static const esp_partition_t* partition_new_firmware = esp_ota_get_next_update_partition(NULL); //get OTA partion to which we will write new firmware file;
        if (upload.status == UPLOAD_FILE_START) { // 阶段1：开始上传（UPLOAD_FILE_START）
            Serial.printf("Update: %s\n", upload.filename.c_str());
            lead_len = 0; // 初始化固件头部数据长度
            // 启动固件更新，UPDATE_SIZE_UNKNOWN 表示固件大小未知 擦除备份区
            if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
                Update.printError(Serial);
            }
        } else if (upload.status == UPLOAD_FILE_WRITE) { // 阶段2：上传中写入数据（UPLOAD_FILE_WRITE）
            /* flashing firmware to ESP*/
            /*
            就是专门用 16 字节的 “小盒子” 只装固件最开头的 16 个字节（固件的 “身份证”），
            同时不管这个小盒子装没装满，收到的每一段固件数据都会完整写入备用 OTA 分区（备份区）；
            等小盒子装满 16 字节后，就只专心往备份区写固件，不再往小盒子存数据了
            */
            if (lead_len < sizeof(lead_bytes)) { /* 第一步：缓存固件头部数据（lead_bytes） */
                uint32_t n = sizeof(lead_bytes)-lead_len; 
                if (n > upload.currentSize) {
                    n = upload.currentSize;
                }
                memcpy(&lead_bytes[lead_len], upload.buf, n); // 拷贝到 lead_bytes 缓存
                lead_len += n;
                if(lead_len >= 16 && !front_16byte_flag )
                {
                    front_16byte_flag = true;
                    Serial.printf("front 16 byte is %d %d %d %d ", lead_bytes[0], lead_bytes[1],lead_bytes[2],lead_bytes[3]); // 打印当前头16个字节
                    Serial.printf("%d %d %d %d ", lead_bytes[4], lead_bytes[5],lead_bytes[6],lead_bytes[7]); // 打印当前头16个字节
                    Serial.printf("%d %d %d %d ", lead_bytes[8], lead_bytes[9],lead_bytes[10],lead_bytes[11]); // 打印当前头16个字节
                    Serial.printf("%d %d %d %d end\n", lead_bytes[12], lead_bytes[13],lead_bytes[14],lead_bytes[15]); // 打印当前头16个字节
                }
            }
            /* 第二步：将固件数据写入 OTA 分区 */
            if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
                Update.printError(Serial); // 写入失败打印错误
            }
        } else if (upload.status == UPLOAD_FILE_END) { // 阶段3：上传完成（UPLOAD_FILE_END）
            // write extra bytes to force flush of the buffer before we check signature
            uint32_t extra = SPI_FLASH_SEC_SIZE+1;
            while (extra--) {
                uint8_t ff = 0xff; 
                Update.write(&ff, 1); // 写入额外的 0xFF 字节，强制刷新 Flash 缓冲区（保证数据写入完成）
            }
            // 核心校验：调用 check_OTA_next() 验证固件合法性 必须签名后才能校验成功 并找到对应的应用描述符
            if (!CheckFirmware::check_OTA_next(partition_new_firmware, lead_bytes, lead_len)) {
                Serial.printf("Update Failed: firmware checks have errors\n");
                server.sendHeader("Connection", "close");
                server.send(500, "text/plain","FAIL");
                delay(5000);
            } else if (Update.end(true)) { // 校验通过，完成更新
                Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
                server.sendHeader("Connection", "close");
                server.send(200, "text/plain","OK");
            } else {  // Update.end() 执行失败
                Update.printError(Serial);
                Serial.printf("Update Failed: Update.end function has errors\n");
                server.sendHeader("Connection", "close");
                server.send(500, "text/plain","FAIL");
                delay(5000);
            }
        }
    });
    Serial.printf("WAP started\n");
    server.begin();
}
/*
该函数是 Web 服务的 “心跳循环”：通过 initialised 标志实现 init() 只执行一次（避免重复初始化），
然后在主循环中反复调用 server.handleClient()，让 ESP32 持续监听并处理 80 端口的 Web 请求，
确保用户访问升级页面、上传固件时能实时响应，是 Web 升级功能 “持续可用” 的基础
*/
void WebInterface::update()
{
    if (!initialised) {
        init();
        initialised = true;
    }
    server.handleClient();
}
