import { prepareZXingModule, writeBarcode } from "zxing-wasm/writer";
import type { ToolInput } from "../../core/io/input-types";
import type { ToolResult } from "../../core/io/output-types";
import type { ToolContext } from "../../core/plugins/plugin-types";
import type { QrCodeGeneratorOptions } from "./index";

const isBrowser = typeof window !== "undefined";
let isPrepared = false;

async function prepareModuleOnce() {
  if (isPrepared) return;

  if (isBrowser) {
    prepareZXingModule({
      overrides: {
        locateFile: (pathName: string) => {
          if (pathName.endsWith(".wasm")) {
            return "/zxing_writer.wasm";
          }
          return pathName;
        },
      },
    });
  } else {
    const path = (await import("path" as string)) as any;
    const fs = (await import("fs" as string)) as any;
    const resolvedPath = path.resolve(
      (globalThis as any).process.cwd(),
      "node_modules/zxing-wasm/dist/writer/zxing_writer.wasm"
    );
    const wasmBinary = fs.readFileSync(resolvedPath);
    prepareZXingModule({
      overrides: {
        wasmBinary,
      },
    });
  }
  isPrepared = true;
}

export async function runQrCodeGenerator(
  input: ToolInput,
  options: QrCodeGeneratorOptions,
  context: ToolContext
): Promise<ToolResult> {
  await prepareModuleOnce();

  const text = (input.text ?? "").trim();
  if (!text) {
    throw new Error("Please enter text or a URL to encode in the QR Code.");
  }

  const { size, margin, errorCorrection, format } = options;

  context.reportProgress({ percentage: 30, message: "Encoding QR Code data..." });

  try {
    const result = await writeBarcode(text, {
      format: "QRCode",
      scale: -size,
      ecLevel: errorCorrection,
      options: `margin=${margin}`,
    });

    if (result.error) {
      throw new Error(result.error);
    }

    context.reportProgress({ percentage: 75, message: "Creating output file..." });

    if (format === "svg") {
      const blob = new Blob([result.svg], { type: "image/svg+xml" });
      context.reportProgress({ percentage: 100, message: "Done" });
      return {
        type: "files",
        files: [
          {
            name: "qrcode.svg",
            mimeType: "image/svg+xml",
            blob,
            sizeAfter: blob.size,
          },
        ],
      };
    } else {
      // png format
      const blob = result.image;
      if (!blob) {
        throw new Error("WebAssembly failed to render the PNG image blob.");
      }
      context.reportProgress({ percentage: 100, message: "Done" });
      return {
        type: "files",
        files: [
          {
            name: "qrcode.png",
            mimeType: "image/png",
            blob,
            sizeAfter: blob.size,
          },
        ],
      };
    }
  } catch (err: any) {
    throw new Error(`Failed to generate QR Code: ${err.message ?? err}`);
  }
}
