"use strict"

const functionArgumentsSearch = require("../../utils/functionArgumentsSearch")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const postcss = require("postcss")

const ruleName = "function-linear-gradient-no-nonstandard-direction"

const messages = ruleMessages(ruleName, {
  rejected: "Unexpected nonstandard direction",
})

function isStandardDirection(source, withToPrefix) {
  const regexp = withToPrefix ? /^to (top|left|bottom|right)(?: (top|left|bottom|right))?$/ : /^(top|left|bottom|right)(?: (top|left|bottom|right))?$/

  const matches = source.match(regexp)
  if (!matches) {
    return false
  }
  if (matches.length === 2) {
    return true
  }
  // Cannot repeat side-or-corner, e.g. "to top top"
  if (matches.length === 3 && matches[1] !== matches[2]) {
    return true
  }
  return false
}

const rule = function (actual) {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, { actual })
    if (!validOptions) {
      return
    }

    root.walkDecls(decl => {
      functionArgumentsSearch(decl.toString().toLowerCase(), "linear-gradient", (expression, expressionIndex) => {
        const firstArg = expression.split(",")[0].trim()

        // If the first character is a number, we can assume the user intends an angle
        if (/[\d\.]/.test(firstArg[0])) {
          if (/^[\d\.]+(?:deg|grad|rad|turn)$/.test(firstArg)) {
            return
          }
          complain()
          return
        }

        // The first argument may not be a direction: it may be an angle,
        // or a color stop (in which case user gets default direction, "to bottom")
        // cf. https://drafts.csswg.org/css-images-3/#linear-gradient-syntax
        if (!/left|right|top|bottom/.test(firstArg)) {
          return
        }

        const withToPrefix = !postcss.vendor.prefix(decl.value)
        if (!isStandardDirection(firstArg, withToPrefix)) {
          complain()
          return
        }

        function complain() {
          report({
            message: messages.rejected,
            node: decl,
            index: expressionIndex,
            result,
            ruleName,
          })
        }
      })
    })
  }
}

rule.ruleName = ruleName
rule.messages = messages
module.exports = rule
