import http from "http";
import { promises as fs } from "fs";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const PORT = Number(process.env.PORT) || 4173;
const distDir = path.resolve(__dirname, "..", "dist");

const emailGenRoot = path.resolve(process.env.EMAIL_GEN_ROOT || path.resolve(__dirname, "..", "..", "email-gen"));
const emailGenProject = process.env.EMAIL_GEN_PROJECT || "vipavenue";
const htmlRelPath = process.env.EMAIL_GEN_HTML_PATH || `emails/${emailGenProject}/html.pug`;
const lettersRelDir = process.env.EMAIL_GEN_LETTERS_DIR || `emails/${emailGenProject}/letters`;
const publicIndexRel = process.env.EMAIL_GEN_PUBLIC_INDEX || "public/index.html";
const allowOrigin = process.env.API_ALLOW_ORIGIN || "*";

const contentTypes = {
  ".html": "text/html; charset=utf-8",
  ".js": "text/javascript; charset=utf-8",
  ".css": "text/css; charset=utf-8",
  ".svg": "image/svg+xml",
  ".png": "image/png",
  ".jpg": "image/jpeg",
  ".jpeg": "image/jpeg",
  ".ico": "image/x-icon",
  ".json": "application/json; charset=utf-8",
  ".map": "application/json; charset=utf-8"
};

const json = (res, status, payload) => {
  res.statusCode = status;
  res.setHeader("Content-Type", "application/json; charset=utf-8");
  res.end(JSON.stringify(payload));
};

const text = (res, status, payload) => {
  res.statusCode = status;
  res.setHeader("Content-Type", "text/plain; charset=utf-8");
  res.end(payload);
};

const safeResolve = (root, rel) => {
  const target = path.resolve(root, rel);
  const safeRoot = root.endsWith(path.sep) ? root : root + path.sep;
  if (!target.startsWith(safeRoot)) {
    throw new Error("Path escapes root");
  }
  return target;
};

const normalizeContentPath = (value = "") =>
  value
    .replace(/^(\.\/)?letters\//i, "")
    .replace(/^\/+/, "")
    .replace(/\.pug$/i, "")
    .trim();

const readBody = (req) =>
  new Promise((resolve, reject) => {
    let data = "";
    req.on("data", (chunk) => {
      data += chunk;
      if (data.length > 5 * 1024 * 1024) {
        reject(new Error("Payload too large"));
        req.destroy();
      }
    });
    req.on("end", () => resolve(data));
    req.on("error", reject);
  });

const server = http.createServer(async (req, res) => {
  try {
    const url = new URL(req.url, `http://${req.headers.host}`);
    const pathname = decodeURIComponent(url.pathname);

    if (pathname === "/api/save") {
      res.setHeader("Access-Control-Allow-Origin", allowOrigin);
      res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
      res.setHeader("Access-Control-Allow-Headers", "Content-Type");
      if (req.method === "OPTIONS") {
        res.statusCode = 204;
        res.end();
        return;
      }
      if (req.method !== "POST") {
        text(res, 405, "Method Not Allowed");
        return;
      }
      const raw = await readBody(req);
      let payload;
      try {
        payload = JSON.parse(raw);
      } catch (e) {
        json(res, 400, { ok: false, error: "Invalid JSON" });
        return;
      }
      const { pugCode, htmlPug, contentPath } = payload || {};
      if (typeof pugCode !== "string" || !pugCode.trim()) {
        json(res, 400, { ok: false, error: "Missing pugCode" });
        return;
      }
      if (typeof htmlPug !== "string" || !htmlPug.trim()) {
        json(res, 400, { ok: false, error: "Missing htmlPug" });
        return;
      }
      if (typeof contentPath !== "string" || !contentPath.trim()) {
        json(res, 400, { ok: false, error: "Missing contentPath" });
        return;
      }

      const normalizedPath = normalizeContentPath(contentPath);
      if (!normalizedPath || normalizedPath.includes("..")) {
        json(res, 400, { ok: false, error: "Invalid contentPath" });
        return;
      }

      const letterRelPath = path.posix.join(lettersRelDir, `${normalizedPath}.pug`);
      const htmlTarget = safeResolve(emailGenRoot, htmlRelPath);
      const letterTarget = safeResolve(emailGenRoot, letterRelPath);

      await fs.mkdir(path.dirname(letterTarget), { recursive: true });
      await fs.writeFile(letterTarget, pugCode, "utf8");
      await fs.writeFile(htmlTarget, htmlPug, "utf8");

      json(res, 200, {
        ok: true,
        saved: {
          letter: letterRelPath,
          html: htmlRelPath
        }
      });
      return;
    }

    if (pathname === "/api/save-html") {
      res.setHeader("Access-Control-Allow-Origin", allowOrigin);
      res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
      res.setHeader("Access-Control-Allow-Headers", "Content-Type");
      if (req.method === "OPTIONS") {
        res.statusCode = 204;
        res.end();
        return;
      }
      if (req.method !== "POST") {
        text(res, 405, "Method Not Allowed");
        return;
      }
      const raw = await readBody(req);
      let payload;
      try {
        payload = JSON.parse(raw);
      } catch (e) {
        json(res, 400, { ok: false, error: "Invalid JSON" });
        return;
      }
      const { htmlPug } = payload || {};
      if (typeof htmlPug !== "string" || !htmlPug.trim()) {
        json(res, 400, { ok: false, error: "Missing htmlPug" });
        return;
      }

      const htmlTarget = safeResolve(emailGenRoot, htmlRelPath);
      await fs.writeFile(htmlTarget, htmlPug, "utf8");

      json(res, 200, {
        ok: true,
        saved: {
          html: htmlRelPath
        }
      });
      return;
    }

    if (pathname === "/api/html") {
      res.setHeader("Access-Control-Allow-Origin", allowOrigin);
      res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
      res.setHeader("Access-Control-Allow-Headers", "Content-Type");
      if (req.method === "OPTIONS") {
        res.statusCode = 204;
        res.end();
        return;
      }
      if (req.method !== "GET" && req.method !== "HEAD") {
        text(res, 405, "Method Not Allowed");
        return;
      }
      const previewPath = safeResolve(emailGenRoot, publicIndexRel);
      try {
        const data = await fs.readFile(previewPath);
        res.statusCode = 200;
        res.setHeader("Content-Type", "text/html; charset=utf-8");
        if (req.method === "HEAD") {
          res.end();
        } else {
          res.end(data);
        }
      } catch (e) {
        text(res, 404, "Preview not found. Run the email generator.");
      }
      return;
    }

    if (pathname === "/preview") {
      if (req.method !== "GET" && req.method !== "HEAD") {
        text(res, 405, "Method Not Allowed");
        return;
      }
      const previewPath = safeResolve(emailGenRoot, publicIndexRel);
      try {
        const data = await fs.readFile(previewPath);
        res.statusCode = 200;
        res.setHeader("Content-Type", "text/html; charset=utf-8");
        if (req.method === "HEAD") {
          res.end();
        } else {
          res.end(data);
        }
      } catch (e) {
        text(res, 404, "Preview not found. Run the email generator.");
      }
      return;
    }

    if (pathname.startsWith("/api/")) {
      text(res, 404, "Not Found");
      return;
    }

    if (req.method !== "GET" && req.method !== "HEAD") {
      text(res, 405, "Method Not Allowed");
      return;
    }

    const safePath = path.resolve(distDir, "." + pathname);
    const safeRoot = distDir.endsWith(path.sep) ? distDir : distDir + path.sep;
    if (!safePath.startsWith(safeRoot)) {
      text(res, 403, "Forbidden");
      return;
    }

    let filePath = safePath;
    try {
      const stat = await fs.stat(filePath);
      if (!stat.isFile()) {
        throw new Error("Not a file");
      }
    } catch (e) {
      filePath = path.join(distDir, "index.html");
    }

    const ext = path.extname(filePath).toLowerCase();
    const contentType = contentTypes[ext] || "application/octet-stream";
    let data;
    try {
      data = await fs.readFile(filePath);
    } catch (e) {
      text(res, 404, "Not Found");
      return;
    }
    res.statusCode = 200;
    res.setHeader("Content-Type", contentType);
    if (req.method === "HEAD") {
      res.end();
    } else {
      res.end(data);
    }
  } catch (e) {
    console.error(e);
    text(res, 500, "Internal Server Error");
  }
});

server.listen(PORT, () => {
  console.log(`editor-svelte server running on http://localhost:${PORT}`);
  console.log(`email-gen root: ${emailGenRoot}`);
});
