"use strict"

const declarationValueIndex = require("../../utils/declarationValueIndex")
const findFontFamily = require("../../utils/findFontFamily")
const report = require("../../utils/report")
const ruleMessages = require("../../utils/ruleMessages")
const validateOptions = require("../../utils/validateOptions")
const keywordSets = require("../../reference/keywordSets")
const _ = require("lodash")
const optionsMatches = require("../../utils/optionsMatches")

const ruleName = "font-family-no-duplicate-names"

const messages = ruleMessages(ruleName, {
  rejected: name => `Unexpected duplicate name ${name}`,
})

const isFamilyNameKeyword = node => !node.quote && keywordSets.fontFamilyKeywords.has(node.value.toLowerCase())

const rule = function (actual, options) {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, { actual }, {
      actual: options,
      possible: {
        ignoreFontFamilyNames: [_.isString],
      },
      optional: true,
    })
    if (!validOptions) {
      return
    }

    root.walkDecls(/^font(-family)?$/i, decl => {
      const keywords = new Set()
      const familyNames = new Set()

      const fontFamilies = findFontFamily(decl.value)

      if (fontFamilies.length === 0) {
        return
      }

      fontFamilies.forEach(fontFamilyNode => {
        const family = fontFamilyNode.value.trim()

        if (optionsMatches(options, "ignoreFontFamilyNames", fontFamilyNode.value.trim())) {
          return
        }

        if (isFamilyNameKeyword(fontFamilyNode)) {
          if (keywords.has(family.toLowerCase())) {
            complain(messages.rejected(family), declarationValueIndex(decl) + fontFamilyNode.sourceIndex, decl)
            return
          }

          keywords.add(family)
          return
        }

        if (familyNames.has(family)) {
          complain(messages.rejected(family), declarationValueIndex(decl) + fontFamilyNode.sourceIndex, decl)
          return
        }

        familyNames.add(family)
      })
    })

    function complain(message, index, decl) {
      report({
        result,
        ruleName,
        message,
        node: decl,
        index,
      })
    }
  }
}

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