#!/usr/bin/env node
import { createServer } from "node:http";
import { create } from "@bufbuild/protobuf";
import { anyUnpack } from "@bufbuild/protobuf/wkt";
import {
  SearchObjectSchema,
  SearchQuerySchema
} from "@orderlyshop/core-client";
import { createOrderlyNodeClient } from "@orderlyshop/core-client/node";

const ORDERLY_SHARE_URL_PREFIX = "https://orderly.shop/";
const DEFAULT_IMAGE_BASE_URL = "https://orderlyproduction.azureedge.net/";

const port = Number.parseInt(process.env.PORT ?? process.env.ORDERLY_PRODUCT_SNAPSHOT_PORT ?? "4107", 10);
const baseUrl = process.env.ORDERLY_BACKEND_URL ?? process.env.VITE_ORDERLY_BASE_URL ?? "https://service.orderly.shop";
const protocol = process.env.ORDERLY_BACKEND_PROTOCOL === "grpc" ? "grpc" : "grpc-web";
const imageBaseUrl = process.env.ORDERLY_IMAGE_BASE_URL ?? process.env.VITE_ORDERLY_IMAGE_BASE_URL ?? DEFAULT_IMAGE_BASE_URL;
const client = createOrderlyNodeClient({ baseUrl, protocol });

const server = createServer(async (request, response) => {
  const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
  if (url.pathname !== "/orderly-product-snapshot") {
    writeJson(response, 404, { error: "Not found" });
    return;
  }

  const shareUrl = normalizeShareUrl(url.searchParams.get("url") ?? "");
  if (!shareUrl) {
    writeJson(response, 400, { error: "Missing url query parameter" });
    return;
  }

  try {
    const result = await client.services.searchService.search(create(SearchQuerySchema, {
      ShareUrl: shareUrl
    }));
    const product = result.data
      .map((item) => anyUnpack(item, SearchObjectSchema))
      .filter(Boolean)[0];

    if (!product) {
      writeJson(response, 404, { error: "Product not found", shareUrl });
      return;
    }

    writeJson(response, 200, productSnapshot(product, shareUrl));
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    writeJson(response, 502, { error: "Could not load product", detail: message });
  }
});

server.listen(port, () => {
  console.log(`Orderly product snapshot server listening on http://localhost:${port}/orderly-product-snapshot`);
});

function productSnapshot(product, fallbackShareUrl) {
  return {
    shareUrl: product.ShareURL?.URL || fallbackShareUrl,
    title: product.Title || "Produkt",
    brand: normalizedBrand(product.Brand),
    description: product.Description || "",
    priceText: formatCredit(product.Price),
    imageUrl: storedImageUrl(product.Images?.[0])
  };
}

function normalizeShareUrl(value) {
  const trimmed = value.trim();
  if (!trimmed || trimmed.startsWith(ORDERLY_SHARE_URL_PREFIX) || /^https?:\/\//i.test(trimmed)) {
    return trimmed;
  }
  return `${ORDERLY_SHARE_URL_PREFIX}${trimmed.replace(/^\/+/, "")}`;
}

function normalizedBrand(brand) {
  const value = brand?.trim();
  if (!value || value.toLowerCase() === "ukendt" || value.toUpperCase() === "DVD") {
    return "";
  }
  return value;
}

function formatCredit(credit) {
  if (!credit) {
    return "";
  }
  const amount = Number(credit.Amount ?? 0);
  const currency = credit.Currency || "";
  const prefix = currency.toUpperCase() === "DKK" ? "kr." : currency.trim();
  const value = amount.toLocaleString("da-DK", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });
  return `${prefix ? `${prefix} ` : ""}${value}`.trim();
}

function storedImageUrl(image) {
  if (!image) {
    return "";
  }
  if (image.ImageDataBase64) {
    return `data:image/jpeg;base64,${image.ImageDataBase64}`;
  }
  if (/^https?:\/\//i.test(image.Name) || image.Name.startsWith("/")) {
    return image.Name;
  }
  if (!image.Name) {
    return "";
  }
  const imageName = image.Name.toLowerCase();
  const path = image.IsAsset || imageName.includes("cms") || imageName.startsWith("images")
    ? "objects"
    : "thumbnails";
  return joinUrl(imageBaseUrl, path, image.Name);
}

function joinUrl(baseUrl, ...parts) {
  const root = String(baseUrl).endsWith("/") ? String(baseUrl) : `${baseUrl}/`;
  return new URL(parts
    .filter(Boolean)
    .map((part) => String(part).replace(/^\/+|\/+$/g, ""))
    .join("/"), root).toString();
}

function writeJson(response, status, value) {
  const body = `${JSON.stringify(value)}\n`;
  response.writeHead(status, {
    "content-type": "application/json; charset=utf-8",
    "cache-control": status === 200 ? "public, max-age=300" : "no-store"
  });
  response.end(body);
}
