/**
 * External dependencies
 */
import { startsWith } from 'lodash';

/**
 * WordPress dependencies
 */
import {
  getProtocol,
  isValidProtocol,
  getAuthority,
  isValidAuthority,
  getPath,
  isValidPath,
  getQueryString,
  isValidQueryString,
  getFragment,
  isValidFragment,
} from '@wordpress/url';
import { __, sprintf } from '@wordpress/i18n';

/**
 * Check for issues with the provided href.
 *
 * @param {string} href The href.
 *
 * @return {boolean} Is the href invalid?
 */
export function isValidHref( href ) {
  if ( ! href ) {
    return false;
  }

  const trimmedHref = href.trim();

  if ( ! trimmedHref ) {
    return false;
  }

  // Does the href start with something that looks like a URL protocol?
  if ( /^\S+:/.test( trimmedHref ) ) {
    const protocol = getProtocol( trimmedHref );
    if ( ! isValidProtocol( protocol ) ) {
      return false;
    }

    // Add some extra checks for http(s) URIs, since these are the most common use-case.
    // This ensures URIs with an http protocol have exactly two forward slashes following the protocol.
    if ( startsWith( protocol, 'http' ) && ! /^https?:\/\/[^\/\s]/i.test( trimmedHref ) ) {
      return false;
    }

    const authority = getAuthority( trimmedHref );
    if ( ! isValidAuthority( authority ) ) {
      return false;
    }

    const path = getPath( trimmedHref );
    if ( path && ! isValidPath( path ) ) {
      return false;
    }

    const queryString = getQueryString( trimmedHref );
    if ( queryString && ! isValidQueryString( queryString ) ) {
      return false;
    }

    const fragment = getFragment( trimmedHref );
    if ( fragment && ! isValidFragment( fragment ) ) {
      return false;
    }
  }

  // Validate anchor links.
  if ( startsWith( trimmedHref, '#' ) && ! isValidFragment( trimmedHref ) ) {
    return false;
  }

  return true;
}

/**
 * Generates the format object that will be applied to the link text.
 *
 * @param {string}  url              The href of the link.
 * @param {boolean} opensInNewWindow Whether this link will open in a new window.
 * @param {Object}  text             The text that is being hyperlinked.
 *
 * @return {Object} The final format object.
 */
export function createLinkFormat( { url, opensInNewWindow, text, noFollow, isSponsored } ) {
  const format = {
    type: 'core/link',
    attributes: {
      url,
    },
  };

  format.attributes.rel = '';

  if ( noFollow ) {
    format.attributes.rel += 'nofollow noindex ';
  }

  if ( isSponsored ) {
    format.attributes.rel += 'sponsored ';
  }

  if ( opensInNewWindow ) {
    // translators: accessibility label for external links, where the argument is the link text
    const label = sprintf( __( '%s (opens in a new tab)' ), text );

    format.attributes.target = '_blank';
    format.attributes.rel += 'noreferrer noopener';

    format.attributes[ 'aria-label' ] = label;
  }

  if ( '' === format.attributes.rel ) {
    delete format.attributes.rel;
  }

  return format;
}
