import axios from "axios";
import chalk from "chalk";
import { LOCAL_SERVER_PORT } from "./localserver/localserver.js";
import {
  createSpinner,
  registerSpinner,
  stopWaiting as stopSpinnerWaiting,
} from "./spinner.js";

const LOG_SECTION_WIDTH = 55;

let sharedCli = null;

export function getCli() {
  return sharedCli;
}

export { startWaiting, stopWaiting } from "./spinner.js";

export function formatState(stateType) {
  switch (stateType) {
    case "online":
      return chalk.green("Online");
    case "offline":
      return chalk.dim("Offline");
    case "error":
      return chalk.red("Error");
    case "inactive":
      return chalk.dim("Inactive");
    case "connecting":
      return chalk.yellow("Connecting");
    case "printing":
      return chalk.blue("Printing");
    case "paused":
      return chalk.yellow("Paused");
    case "cancelled":
      return chalk.red("Cancelled");
    case "completed":
      return chalk.green("Completed");
    default:
      return chalk.dim("Unknown");
  }
}

export function createCliLogger(logger) {
  const spinner = createSpinner();
  registerSpinner(spinner);

  function withSpinnerStopped(fn) {
    return async (...args) => {
      await stopSpinnerWaiting();
      return fn(...args);
    };
  }

  function logSectionHeader(title) {
    const padding = LOG_SECTION_WIDTH - title.length;
    const left = Math.floor(padding / 2);
    const right = padding - left;
    logger.info(
      chalk.dim.cyan("-".repeat(left)) +
        chalk.bold.white(title) +
        chalk.dim.cyan("-".repeat(right)),
    );
  }

  function logSectionFooter() {
    logger.info(chalk.dim.cyan("-".repeat(LOG_SECTION_WIDTH)));
  }

  const cli = {
    waiting(message) {
      spinner.start(message, logger);
    },

    async stopWaiting() {
      await stopSpinnerWaiting();
    },

    blank: withSpinnerStopped(() => {
      process.stdout.write("  \n");
    }),

    success: withSpinnerStopped((message, ...rest) => {
      logger.info(chalk.bold.white(`✔ `) + chalk.bold.green(message), ...rest);
    }),

    failure: withSpinnerStopped((message, ...rest) => {
      logger.error(chalk.bold.white(`✘ `) + chalk.bold.red(message), ...rest);
    }),

    warn: withSpinnerStopped((message, ...rest) => {
      logger.warn(chalk.yellow(message), ...rest);
    }),

    info: withSpinnerStopped((message, ...rest) => {
      logger.info(message, ...rest);
    }),

    secure: withSpinnerStopped((message) => {
      logger.info(chalk.cyan(`🔒 ${message}`));
    }),

    label: withSpinnerStopped((key, value) => {
      if (value == undefined) {
        logger.info(key);
      } else {
        logger.info(chalk.bold(key), value);
      }
    }),

    yesNo(value) {
      return value ? chalk.green("Yes") : chalk.yellow("No");
    },

    formatState,

    sectionHeader: withSpinnerStopped(logSectionHeader),
    sectionFooter: withSpinnerStopped(logSectionFooter),
  };

  sharedCli = cli;
  return cli;
}

export function hasFlag(name) {
  return (
    process.argv.includes(`--${name}`) || process.argv.includes(`-${name}`)
  );
}

export function getFlagValue(name) {
  for (const prefix of [`--${name}`, `-${name}`]) {
    const withEquals = process.argv.find((arg) => arg.startsWith(`${prefix}=`));
    if (withEquals) {
      return withEquals.slice(prefix.length + 1);
    }

    const index = process.argv.indexOf(prefix);
    if (index !== -1 && index + 1 < process.argv.length) {
      const next = process.argv[index + 1];
      if (!next.startsWith("-")) {
        return next;
      }
    }
  }

  return undefined;
}

export const isHeadless = process.argv.includes("--headless");

export function printerHostInfo(host, cli) {
  let ref = host?._reference || "Unknown";

  if (ref !== "Unknown") {
    ref = `HST:${ref}`;
  }

  cli.label("Reference:", ref);
  cli.label("Name:", host?.name || "Unknown");

  if (host?.tags?.length > 0) {
    cli.label("Tags:", chalk.dim(`- `) + chalk.blue(`${host.tags[0]}`));
    for (let i = 0; i < host.tags.length - 1; i++) {
      const tag = host.tags[i + 1];
      cli.info(chalk.dim(`      - `) + chalk.blue(`${tag}`));
    }
  } else {
    cli.label("Tags:", chalk.dim("n/a"));
  }

  cli.label("State:", cli.formatState(host?.state?.type));
}

export function printAuthCommand(cli) {
  cli.info(
    "Run '" +
      chalk.bold.magentaBright("farmcontrol-server") +
      " " +
      chalk.bold.magentaBright("--otp") +
      " " +
      chalk.dim.white("<otp>") +
      "' to authenticate.",
  );
}

export async function checkRunning() {
  try {
    const response = await axios.get(
      `http://127.0.0.1:${LOCAL_SERVER_PORT}/info`,
      { timeout: 1000 },
    );
    if (response.data?.running === true) {
      return response.data;
    }
  } catch {
    return false;
  }
}

export async function authenticateWithOtp(code) {
  try {
    const response = await axios.post(
      `http://127.0.0.1:${LOCAL_SERVER_PORT}/otpAuth`,
      { otp: code },
      { timeout: 30000 },
    );
    return response.data;
  } catch (err) {
    if (err.response?.data) {
      return err.response.data;
    }
    throw new Error("Failed to authenticate with OTP");
  }
}

export async function setLogLevel(level) {
  try {
    const response = await axios.post(
      `http://127.0.0.1:${LOCAL_SERVER_PORT}/logLevel`,
      { logLevel: level },
      { timeout: 5000 },
    );
    return response.data;
  } catch (err) {
    if (err.response?.data) {
      return err.response.data;
    }
    throw new Error("Failed to set log level");
  }
}
