/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import { open } from "node:fs/promises";
import { resolve } from "node:path";
import { pipeline } from "node:stream/promises";
import { Writable, type TransformCallback } from "node:stream";
import { HeaderValue, HeaderKeyFactory } from "../index.js";
import { getClient } from "./utils.js";

export const fileToTopic = async (
  filepath: string,
  streamName: string,
  topicName: string,
  highWaterMark = 512 * 1024,
) => {
  const cli = getClient();
  await cli.stream.ensure(streamName);
  await cli.topic.ensure(streamName, topicName);
  const fd = await open(filepath);
  const fname = filepath.split("/").pop() || filepath;
  const st = await fd.stat();
  console.log(
    "FILE/STAT",
    fname,
    "~",
    (st.size / (1024 * 1024)).toFixed(2),
    "mb",
    st,
  );
  const dStart = Date.now();

  try {
    let idx = 0;

    await pipeline(
      fd.createReadStream({ highWaterMark }),

      new Writable({
        async write(
          chunks: Buffer,
          encoding: BufferEncoding,
          cb: TransformCallback,
        ) {
          const messages = [
            {
              headers: [
                {
                  key: HeaderKeyFactory.String("fileindex"),
                  value: HeaderValue.Uint32(idx++),
                },
                {
                  key: HeaderKeyFactory.String("filename"),
                  value: HeaderValue.String(fname),
                },
              ],
              payload: chunks,
            },
          ];

          try {
            await cli.message.send({
              streamId: streamName,
              topicId: topicName,
              messages,
            });
            cb();
          } catch (err) {
            console.log("WRITE ERR", err, chunks);
            cb(err as Error);
          }
        },
      }),
    );

    console.log(`Finished ! took ${Date.now() - dStart}ms`);
  } catch (err) {
    console.error("Pipeline failed !", err);
    throw err;
  }
};

const argz = process.argv.slice(2);
const [rPath, streamIdStr, topicIdStr] = argz;

if (argz.length < 3 || ["-h", "--help", "?"].includes(argz[0])) {
  console.log(
    `Usage: node stream-file-to-topic.js filePath streamName topicName`,
  );
  console.log("got", argz);
  console.log("note: this script only accept numerical stream/topic id");
  process.exit(1);
}

const filepath = resolve(rPath);
const streamName = streamIdStr;
const topicName = topicIdStr;

console.log("running with params:", { filepath, streamName, topicName });

try {
  await fileToTopic(filepath, streamName, topicName, 512 * 1024);
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
  process.exit(1);
}

process.exit(0);
