import type { Server, ServerWebSocket } from "bun";
import SSSG, { Plugin } from "..";
import * as fs from "fs";
import mime from "mime-types";

const script = `let reconnectTimeout,waitingForReconnect=!1;function connect(){console.log("[dev] connecting to dev server");var e=new WebSocket("ws://localhost:8080");e.addEventListener("message",e=>{"refresh"==e.data&&location.reload()}),e.addEventListener("open",()=>{console.log("[dev] connected"),waitingForReconnect&&location.reload()}),e.addEventListener("close",()=>{console.log("[dev] socket closed, restarting in 1s"),clearTimeout(reconnectTimeout),reconnectTimeout=setTimeout(()=>{connect(),waitingForReconnect=!0},1e3)})}window.addEventListener("load",()=>connect());`;

export default class DevPlugin extends Plugin {
  build: undefined;
  
  name = "dev";
  rewriteTriggers = [];
  renameTo = undefined;
  longLasting = true;
  server!: Server;
  allConnections: ServerWebSocket<number>[] = [];
    
  constructor(sssg: SSSG, headers: Record<string, string>) {
    super();

    fs.watch(
      sssg.inputFolder,
      {
        recursive: true,
      },
      async (e, f) => {
        console.log("[dev] Noticed update in " + f + ", of type " + e + ".");
        this.allConnections.forEach((z) => z.send("refresh"));
        await sssg.build();
      }
    );

    this.server = Bun.serve<number>({
      fetch(req, server) {
        const success = server.upgrade(req);
        if (success) {
          return undefined;
        }

        const url = new URL(req.url);

        let cleanedPath = url.pathname;
        if (cleanedPath == "/") cleanedPath = "/index.html";
        if (cleanedPath.endsWith("/")) cleanedPath = cleanedPath.slice(0, -1);

        let fsPath = sssg.outputFolder + cleanedPath;

        if (fsPath.match(/\.\.\//g) !== null) {
          return undefined;
        }
        let rawFile;
        try {
          rawFile = fs.readFileSync(fsPath);
        } catch {
          return new Response("404 Not Found", {
            status: 404,
          });
        }
        const type = fsPath.split(".").at(-1);
        if (!type) return;
        if (type == "html") {

          rawFile = rawFile.toString().replace(
            "<head>",
            `<head><script>${script}</script>`
          );
        }
        return new Response(rawFile, {
          headers: {
            "Cache-Control": "no-cache, no-store, must-revalidate",
            "Pragma": "no-cache",
            "Expires": "0",
            "Content-Type": (mime.lookup(type) || "application/octet-stream") + "; charset=utf-8",
            ...headers
          },
        });
      },
      websocket: {
        open: (ws) => {
          ws.data = Math.random();

          this.allConnections.push(ws);
        },
        message(ws, message) {},
        close: (ws) => {
          this.allConnections = this.allConnections.filter(
            (z) => z.data != ws.data
          );
        },
      },
      port: 8080,
    });
  }

  async rewriteFile(file: string, filePath: string) {
    return undefined;
  }
}
