import { computeValue } from "../../../core";
import { assert, isNil } from "../../../util";
import {
  adjustDate,
  computeDate,
  DATE_FORMAT,
  DATE_FORMAT_SYM_RE,
  DATE_SYM_TABLE,
  formatTimezone,
  padDigits,
  parseTimezone
} from "./_internal";
import { $dayOfMonth } from "./dayOfMonth";
import { $dayOfWeek } from "./dayOfWeek";
import { $dayOfYear } from "./dayOfYear";
import { $hour } from "./hour";
import { $isoDayOfWeek } from "./isoDayOfWeek";
import { $isoWeek } from "./isoWeek";
import { $millisecond } from "./millisecond";
import { $minute } from "./minute";
import { $month } from "./month";
import { $second } from "./second";
import { $week } from "./week";
import { $year } from "./year";
const DATE_FUNCTIONS = {
  "%Y": $year,
  "%G": $year,
  "%m": $month,
  "%d": $dayOfMonth,
  "%H": $hour,
  "%M": $minute,
  "%S": $second,
  "%L": $millisecond,
  "%u": $isoDayOfWeek,
  "%U": $week,
  "%V": $isoWeek,
  "%j": $dayOfYear,
  "%w": (o, e, p) => $dayOfWeek(o, e, p) - 1
};
const $dateToString = (obj, expr, options) => {
  const args = computeValue(obj, expr, null, options);
  if (isNil(args.onNull)) args.onNull = null;
  if (isNil(args.date)) return args.onNull;
  const date = computeDate(obj, args.date, options);
  let format = args.format || DATE_FORMAT;
  const minuteOffset = parseTimezone(args.timezone);
  const matches = format.match(DATE_FORMAT_SYM_RE);
  adjustDate(date, minuteOffset);
  for (let i = 0, len = matches.length; i < len; i++) {
    const formatSpecifier = matches[i];
    assert(
      formatSpecifier in DATE_SYM_TABLE,
      `$dateToString: invalid format specifier ${formatSpecifier}`
    );
    const { name, padding } = DATE_SYM_TABLE[formatSpecifier];
    const fn = DATE_FUNCTIONS[formatSpecifier];
    let value;
    if (fn) {
      value = padDigits(fn(obj, date, options), padding);
    } else {
      switch (name) {
        case "timezone":
          value = formatTimezone(minuteOffset);
          break;
        case "minute_offset":
          value = minuteOffset.toString();
          break;
        case "abbr_month":
        case "full_month": {
          const format2 = name.startsWith("abbr") ? "short" : "long";
          value = date.toLocaleString("en-US", { month: format2 });
          break;
        }
      }
    }
    format = format.replace(formatSpecifier, value);
  }
  return format;
};
export {
  $dateToString
};
