const fs = require("fs");
const path = require("path");
const { purchaseTopup } = require("../automation/smileOneAutomation");
const { request } = require("../services/apiClient");
const { selectAccount } = require("../services/smileAccountRouter");
const { loadEnv } = require("../utils/env");
const logger = require("../utils/logger");

loadEnv();

function boolFromEnv(name, fallback) {
  const raw = process.env[name];
  if (raw === undefined) return fallback;
  return ["1", "true", "yes", "on"].includes(raw.toLowerCase());
}

function numberFromEnv(name, fallback) {
  const value = Number(process.env[name]);
  return Number.isFinite(value) ? value : fallback;
}

function getConfig() {
  return {
    dryRun: boolFromEnv("AUTOMATION_DRY_RUN", true),
    intervalSeconds: numberFromEnv("AUTOMATION_INTERVAL_SECONDS", 20),
    maxAttempts: numberFromEnv("AUTOMATION_MAX_ATTEMPTS", 2),
    delayMs: numberFromEnv("AUTOMATION_DELAY_MS", 2500),
    routingStrategy: process.env.SMILE_ROUTING_STRATEGY || "balance-aware",
    queueStateFile: path.join(__dirname, "..", "..", "live-checking", "state", "queue-status.json"),
  };
}

function writeQueueState(state) {
  fs.mkdirSync(path.dirname(state.file), { recursive: true });
  fs.writeFileSync(
    state.file,
    JSON.stringify(
      {
        ok: state.ok,
        pending: state.pending,
        failed: state.failed,
        message: state.message,
        timestamp: new Date().toISOString(),
      },
      null,
      2
    )
  );
}

async function markQueue(orderId, action, detail = "") {
  return request(`/api/admin/queue/${encodeURIComponent(orderId)}/${action}`, {
    method: "POST",
    body: JSON.stringify({ detail }),
  });
}

async function processNextOrder() {
  const config = getConfig();
  const [{ queue }, { accounts }] = await Promise.all([
    request("/api/admin/queue"),
    request("/api/admin/smile-accounts"),
  ]);
  const waiting = queue.filter((item) => item.status === "waiting" && item.attempts < config.maxAttempts);
  const failed = queue.filter((item) => item.status === "failed").length;

  writeQueueState({
    file: config.queueStateFile,
    ok: failed === 0,
    pending: waiting.length,
    failed,
    message: failed > 0 ? "One or more automation jobs failed" : "",
  });

  if (waiting.length === 0) {
    logger.info("No waiting automation jobs", { failed });
    return { processed: false };
  }

  const order = waiting[0];
  await markQueue(order.order_id, "process", "automation worker picked order");

  try {
    const account = selectAccount(accounts, order, config.routingStrategy);
    const result = await purchaseTopup({
      order,
      account,
      dryRun: config.dryRun,
      delayMs: config.delayMs,
    });
    await markQueue(order.order_id, "complete", result.reference || "automation completed");
    logger.info("Automation job completed", {
      orderId: order.order_id,
      reference: result.reference,
      dryRun: result.dryRun,
    });
    return { processed: true, orderId: order.order_id };
  } catch (error) {
    await markQueue(order.order_id, "fail", error.message);
    logger.error("Automation job failed", {
      orderId: order.order_id,
      error: error.message,
    });
    return { processed: false, orderId: order.order_id, error: error.message };
  }
}

async function runLoop() {
  const config = getConfig();
  logger.info("Automation worker started", {
    intervalSeconds: config.intervalSeconds,
    dryRun: config.dryRun,
  });

  while (true) {
    try {
      await processNextOrder();
    } catch (error) {
      logger.error("Automation worker cycle failed", {
        error: error.message,
      });
    }
    await new Promise((resolve) => setTimeout(resolve, config.intervalSeconds * 1000));
  }
}

if (require.main === module) {
  const once = process.argv[2] === "once";
  const runner = once ? processNextOrder : runLoop;
  runner().catch((error) => {
    logger.error("Automation worker failed", {
      error: error.message,
      stack: error.stack,
    });
    process.exit(1);
  });
}

module.exports = {
  processNextOrder,
};
