import { Children, isValidElement } from "react";

export const toCamelCase = (str: string) => {
  const s = str
    .toLowerCase()
    .replace(/[-_\s.]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""));
  return s.substring(0, 1).toLowerCase() + s.substring(1);
};

export const toKebabCase = (str: string) => {
  return str
    .toLowerCase()
    .replace(/[\s_]+/g, "-")
    .replace(/[']+/g, "")
    .replace(/[^a-z0-9-]/g, "");
};

export const toTitleCase = (str: string, delimiters: string[] = []) => {
  const defaultDelimiters = ["-", "_", " "];
  const allDelimiters = defaultDelimiters.concat(delimiters).join("");

  return (
    str
      // Capitalize the first non-delimiter character of the string
      .replace(
        new RegExp(`^[${allDelimiters}]*([^${allDelimiters}])`),
        (_, char) => char.toUpperCase(),
      )
      // Replace each group of delimiters with a space and capitalize the following character
      .replace(
        new RegExp(`[${allDelimiters}]+([^${allDelimiters}])`, "g"),
        (_, char) => " " + char.toUpperCase(),
      )
  );
};

// Adds a non-breaking unicode character between the last two words of a string
// in order to prevent typographical widows (i.e., a line with a single word).
export const UNICODE_NO_BREAK_SPACE = "\u00a0";
export const UNICODE_NON_BREAKING_HYPHEN = "\u2011";
export const LAST_SPACE_REGEX = /([^\s])\s+([^\s]+)(\s*)$/;
export const widont = (
  str: string,
  opts: { preserveTrailingWhitespace: boolean } = {
    preserveTrailingWhitespace: false,
  },
) => {
  const dashRegex = /-/g;

  return str.replace(
    LAST_SPACE_REGEX,
    (_, precedingChar, lastWord, trailingWhitespace) => {
      // Prefer replacing hyphens inside last word if present
      if (lastWord.includes("-")) {
        return (
          precedingChar +
          " " +
          lastWord.replace(dashRegex, UNICODE_NON_BREAKING_HYPHEN) +
          (opts.preserveTrailingWhitespace ? trailingWhitespace : "")
        );
      }
      return (
        precedingChar +
        UNICODE_NO_BREAK_SPACE +
        lastWord +
        (opts.preserveTrailingWhitespace ? trailingWhitespace : "")
      );
    },
  );
};

export const extractTextFromReactNode = (node: React.ReactNode): string => {
  const extract = (child: React.ReactNode): string => {
    if (typeof child === "string") {
      return child.trim() + " ";
    } else if (isValidElement(child)) {
      return Children.toArray(child.props.children).map(extract).join("");
    }
    return "";
  };

  return Children.toArray(node).map(extract).join("").trim();
};
