
// HTML шаблоны в PROGMEM
const char PAGE_HEADER[] PROGMEM = R"=====(
<!DOCTYPE html><html><head>
<meta charset=UTF-8>
<meta name=viewport content='width=device-width,initial-scale=1'>
<title>PreSetup</title>
<style>
body{font-family:Arial,sans-serif;margin:15px;padding:0;background:#f5f5f5}
h1,h2{color:#333;margin:5px 0}
input,button,select{display:block;width:100%;margin:5px 0;padding:8px;box-sizing:border-box;border:1px solid #ddd;border-radius:3px}
button{background:#007bff;color:white;border:none;cursor:pointer;font-weight:bold}
button:hover{opacity:0.9}
button.danger{background:#dc3545}
button.warning{background:#ffc107}
button.success{background:#28a745}
.sc{background:white;margin:10px 0;padding:15px;border-radius:5px;box-shadow:0 1px 3px rgba(0,0,0,0.1)}
.fl{max-height:300px;overflow-y:auto;border:1px solid #ddd;padding:10px;margin:10px 0;background:#fafafa}
.fi{display:table;width:100%;margin:5px 0;padding:8px;border-bottom:1px solid #eee;box-sizing:border-box;font-size:16px}
.fn{display:table-cell;width:60%;word-break:break-all;vertical-align:middle}
.fs{color:#666;font-size:14px;margin-left:8px}
.dw{display:table-cell;width:20%;padding:6px;font-size:14px;background:#28a745;color:white;border:none;border-radius:4px;cursor:pointer;text-align:center;white-space:nowrap;min-width:50px;margin:0 5px}
.dw:hover{background:#218838}
.db{display:table-cell;width:20%;padding:6px;font-size:14px;background:#c82333;color:white;border:none;border-radius:4px;cursor:pointer;text-align:center;white-space:nowrap;min-width:50px}
.db:hover{background:#a71e2a}
.st{color:#666;font-size:14px;margin:5px 0}
.al{position:fixed;top:20px;left:50%;transform:translateX(-50%);background:#28a745;color:white;padding:12px 24px;border-radius:5px;z-index:1000;display:none;font-size:16px}
.eb{background:#6c757d;margin-top:20px;text-align:center;font-size:16px;padding:10px}
.eb:hover{background:#5a6268}
</style>
</head><body>
<div class=al id=al></div>
<div style='max-width:600px;margin:0 auto'>
<h1>⚙️ Samovarich PreSetup</h1>
)=====";

const char STORAGE_SECTION[] PROGMEM = R"=====(
<div class=sc>
<h3>📊 Storage: %UP%% (%UB% of %TB%)</h3>
<div style='background:#ddd;border-radius:5px;height:20px;margin:10px 0'>
<div style='background:%FC%;height:100%;border-radius:5px;width:%UP%%'></div>
</div>
</div>
)=====";

const char PAGE_FOOTER[] PROGMEM = R"=====(
<div style='margin-top:30px;text-align:center'>
<a href='/' style='text-decoration:none'><button class='eb'>🚪 Exit to Main</button></a>
</div>
</div>
<script>
function sa(m,t){
 var al=document.getElementById('al');
 al.style.display='block';
 al.textContent=m;
 al.style.background=t==='error'?'#dc3545':'#28a745';
 setTimeout(()=>al.style.display='none',3000)
}
function sWF(){
 var s=document.getElementById('ssid').value;
 var p=document.getElementById('pas').value;
 fetch('/wifi_save',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},
 body:'ssid='+encodeURIComponent(s)+'&pas='+encodeURIComponent(p)})
 .then(r=>r.text()).then(d=>{sa(d,'success');setTimeout(()=>location.reload(),2000)})
 .catch(e=>sa('Error: '+e,'error'));
 return false
}
function ffs(){
 if(confirm('⚠️ Delete ALL files?')) 
 fetch('/format_fs',{method:'POST'})
 .then(r=>r.text()).then(d=>{sa(d,'success');setTimeout(()=>location.reload(),1000)})
 .catch(e=>sa('Error: '+e,'error'))
}
function df(f){
 window.open('/download?file='+encodeURIComponent(f),'_blank')
}
function dlf(f){
 if(confirm('Delete '+f+'?')) 
 fetch('/delete_file?file='+encodeURIComponent(f),{method:'POST'})
 .then(r=>r.text()).then(d=>{sa(d,'success');setTimeout(()=>location.reload(),1000)})
 .catch(e=>sa('Error: '+e,'error'))
}
function hU(e){
 e.preventDefault();
 var formData=new FormData(document.getElementById('UpF'));
 fetch('/upload',{method:'POST',body:formData})
 .then(r=>r.text()).then(d=>{sa('Files uploaded successfully','success');setTimeout(()=>location.reload(),1000)})
 .catch(e=>sa('Upload error: '+e,'error'))
}
document.getElementById('UpF').addEventListener('submit',hU);
</script>
</body></html>
)=====";

const char WIFI_SECTION[] PROGMEM = R"=====(
<div class=sc>
<h2>📶 WiFi Settings</h2>
<form onsubmit='return sWF()'>
<input type=text id=ssid placeholder='WiFi SSID' required>
<input type=password id=pas placeholder='pas' required>
<button type=submit>💾 Save & Reboot</button>
</form>
</div>
)=====";

const char FS_SECTION[] PROGMEM = R"=====(
<div class=sc>
<h2>📁 File System</h2>
<button class=warning onclick='ffs()'>🗑️ Format FS</button>
<div class=st id=fsStatus>%FS%</div>

<h3>📤 Upload Files</h3>
<form id=UpF method=post enctype=multipart/form-data>
<input type=file name=file multiple required>
<button type=submit>⬆️ Upload Selected</button>
</form>

<h3>📋 Existing Files:</h3>
<div class=fl>%FL%</div>
</div>
)=====";

void handleUploadRequest(AsyncWebServerRequest *request) {
  request->send(200, "text/plain", "Upload complete");
}

void handleUploadData(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
  static File uploadFile;
  if (!index) {
    String fname = filename;
    if (fname[0] != '/') fname = "/" + fname;
    uploadFile = SPIFFS.open(fname, "w");
    DbgMsg("Upload: " + fname, 1);
  }
   vTaskDelay(10/portTICK_PERIOD_MS); 
  if (uploadFile && len) {
    uploadFile.write(data, len);
  }
   vTaskDelay(10/portTICK_PERIOD_MS); 
  if (final && uploadFile) {
    uploadFile.close();
    //DbgMsg("UploadEnd: " + filename, 1);
  }
}
void handleDownloadFile(AsyncWebServerRequest *request) {
  if (request->hasParam("file")) {
    String filename = request->getParam("file")->value();
    if (filename[0] != '/') filename = "/" + filename;
    
    if (SPIFFS.exists(filename)) {
      request->send(SPIFFS, filename, "application/octet-stream", true);
    } else {
      request->send(404, "text/plain", "File not found");
    }
  } else {
    request->send(400, "text/plain", "File parameter required");
  }
}
void setupTechnicalWebHandlers() {
  server.on("/technical", HTTP_GET, handleTechnicalPage);
  server.on("/wifi_save", HTTP_POST, handleWifiSave);
  server.on("/format_fs", HTTP_POST, handleFormatFS);
  server.on("/delete_file", HTTP_POST, handleDeleteFile);
  server.on("/upload", HTTP_POST, handleUploadRequest, handleUploadData);
  server.on("/download", HTTP_GET, handleDownloadFile); 
}

void handleTechnicalPage(AsyncWebServerRequest *request) {
  request->send(200, "text/html", getTechnicalPage());
}

void handleWifiSave(AsyncWebServerRequest *request) {
  if (request->hasParam("ssid", true) && request->hasParam("pas", true)) {
    String ssid = request->getParam("ssid", true)->value();
    String pas = request->getParam("pas", true)->value();
    
    strlcpy(SamSetup.SavedSSID, ssid.c_str(), sizeof(SamSetup.SavedSSID));
    strlcpy(SamSetup.SavedPASS, pas.c_str(), sizeof(SamSetup.SavedPASS));
    
    save_profile();
    request->send(200, "text/plain", "WiFi saved. Rebooting...");
    delay(1000);
    ESP.restart();
  } else {
    request->send(400, "text/plain", "Need SSID and password");
  }
}

void handleFormatFS(AsyncWebServerRequest *request) {
  if (SPIFFS.begin(true)) {
    BrokenFS = false;
    request->send(200, "text/plain", "FS formatted successfully");
  } else {
    vTaskDelay(100/portTICK_PERIOD_MS); 
    if (SPIFFS.begin(true)){ //две попытки форматирования
      BrokenFS = false;
      request->send(200, "text/plain", "FS formatted successfully");
    } else
      request->send(500, "text/plain", "Format error");
  }
}

void handleDeleteFile(AsyncWebServerRequest *request) {
  if (request->hasParam("file")) {
    String filename = request->getParam("file")->value();
    if (filename[0] != '/') filename = "/" + filename;
    
    if (SPIFFS.exists(filename)) {
      SPIFFS.remove(filename);
      request->send(200, "text/plain", "File deleted: " + filename);
    } else {
      request->send(404, "text/plain", "File not found");
    }
  } else {
    request->send(400, "text/plain", "File parameter required");
  }
}

String getTechnicalPage() {
  String page;
  page.reserve(2500);
  
  // Header
  page += FPSTR(PAGE_HEADER);
  
  // WiFi section
  page += FPSTR(WIFI_SECTION);
  
  // File system section
  String fsSection = FPSTR(FS_SECTION);
  String statusText = BrokenFS ? "❌ File system not ready" : "✅ File system ready";
  fsSection.replace("%FS%", statusText);

  vTaskDelay(10/portTICK_PERIOD_MS); 
  String fileList = getFileListHTML();
   vTaskDelay(10/portTICK_PERIOD_MS); 
  
  fsSection.replace("%FL%", fileList);
  page += fsSection;
   vTaskDelay(10/portTICK_PERIOD_MS); 
  if (BrokenFS || !SPIFFS.begin(false)) {
    page += "<div class=sc><h3>📊 Storage: Not Available</h3></div>";
  } else {
    size_t total = SPIFFS.totalBytes();
    size_t used = SPIFFS.usedBytes();
    size_t free = total - used;
    int usedPercent = total > 0 ? (used * 100) / total : 0;
    
    String color = "#28a745";
    if (usedPercent > 90) color = "#dc3545";
    else if (usedPercent > 75) color = "#ffc107";
     vTaskDelay(10/portTICK_PERIOD_MS); 
    String storageHTML = FPSTR(STORAGE_SECTION);
    storageHTML.replace("%TB%", formatBytes(total));
    storageHTML.replace("%UB%", formatBytes(used));
    storageHTML.replace("%UP%", String(usedPercent));
    storageHTML.replace("%FC%", color);
    
    page += storageHTML;
  }
   vTaskDelay(10/portTICK_PERIOD_MS); 
  page += FPSTR(PAGE_FOOTER);
  
  return page;
}

String getFileListHTML() {
  if (BrokenFS || !SPIFFS.begin(false)) {
    return "<div style='color:red'>❌ File system not ready</div>";
  }
  
  String fileList;
  File root = SPIFFS.open("/");
  File file = root.openNextFile();
  int fileCount = 0;
  
  while (file && (fileCount < 51)) { //Показываем не более 50 файлов !!!
    if (!file.isDirectory()) {
      fileCount++;
      String filename = file.name();
      String filesize = String(file.size());
      
      fileList += "<div class='fi'>";
      fileList += "<span class='fn'>📄 " + filename + " <span class='fs'>(" + filesize + "b)</span></span>";
      fileList += "<button class='dw' onclick='df(\"" + filename + "\")'>📥</button>";
      fileList += "<button class='db' onclick='dlf(\"" + filename + "\")'>🗑️</button>";
      fileList += "</div>";
    }
    file = root.openNextFile();
  }
  
  if (fileCount == 0) {
    fileList = "<div style='color:#666;text-align:center'>📭 No files found</div>";
  }
  
  return fileList;
}