#!/usr/bin/env node

// simple nodejs script to test sdnext api

const fs = require('fs');
const path = require('path');
const process = require('process');
const argparse = require('argparse');

const sd_url = process.env.SDAPI_URL || 'http://127.0.0.1:7860';
const sd_username = process.env.SDAPI_USR;
const sd_password = process.env.SDAPI_PWD;
let args = {};

function b64(file) {
  const data = fs.readFileSync(file);
  const b64str = Buffer.from(data).toString('base64');
  const ext = path.extname(file).replace('.', '');
  const str = `data:image/${ext};base64,${b64str}`;
  // console.log('b64:', ext, b64.length);
  return str;
}

function options() {
  const opt = {
    // first pass
    prompt: args.prompt || 'beautiful lady, in the steampunk style',
    negative_prompt: args.negative || 'foggy, blurry',
    seed: -1,
    steps: 20,
    batch_size: 1,
    n_iter: 1,
    cfg_scale: 6,
    width: args.width || 1024,
    height: args.height || 1024,
    // api return options
    save_images: false,
    send_images: true,
  };
  if (args.pulid) {
    const b64image = b64(args.pulid);
    opt.script_name = 'pulid';
    opt.script_args = [
      b64image, // b64 encoded image, required param
      0.9, // strength, optional
      20, // zero, optional
      'dpmpp_sde', // sampler, optional
      'v2', // ortho, optional
      true, // restore (disable pulid after run), optional
      true, // offload, optional
      'v1.1', // version, optional
    ];
  }
  // console.log('options:', opt);
  return opt;
}

function init() {
  const parser = new argparse.ArgumentParser({ description: 'SD.Next API' });
  parser.add_argument('--prompt', { type: 'str', help: 'prompt' });
  parser.add_argument('--negative', { type: 'str', help: 'negative' });
  parser.add_argument('--width', { type: 'int', help: 'width' });
  parser.add_argument('--height', { type: 'int', help: 'height' });
  parser.add_argument('--pulid', { type: 'str', help: 'pulid init image' });
  parser.add_argument('--output', { type: 'str', help: 'output path' });
  const parsed = parser.parse_args();
  return parsed;
}

async function main() {
  const method = 'POST';
  const headers = new Headers();
  const opt = options();
  const body = JSON.stringify(opt);
  headers.set('Content-Type', 'application/json');
  if (sd_username && sd_password) headers.set({ Authorization: `Basic ${btoa('sd_username:sd_password')}` });
  const res = await fetch(`${sd_url}/sdapi/v1/txt2img`, { method, headers, body });

  if (res.status !== 200) {
    console.log('Error', res.status);
  } else {
    const json = await res.json();
    console.log('result:', json.info);
    for (const i in json.images) { // eslint-disable-line guard-for-in
      const file = args.output || `/tmp/test-${i}.jpg`;
      const data = atob(json.images[i]);
      fs.writeFileSync(file, data, 'binary');
      console.log('image saved:', file);
    }
  }
}

args = init();
main();
