'use strict'
/* eslint-disable node/no-deprecated-api */

const url = require('url')
const defaults = require('../../config/defaults')

/**
 * Represents the URI that a Solid server is installed on, and manages user
 * account URI creation.
 *
 * @class SolidHost
 */
class SolidHost {
  /**
   * @constructor
   * @param [options={}]
   * @param [options.port] {number}
   * @param [options.serverUri] {string} Fully qualified URI that this Solid
   *   server is listening on, e.g. `https://solid.community`
   * @param [options.live] {boolean} Whether to turn on WebSockets / LDP live
   * @param [options.root] {string} Path to root data directory
   * @param [options.multiuser] {boolean} Multiuser mode
   * @param [options.webid] {boolean} Enable WebID-related functionality
   *  (account creation and authentication)
   */
  constructor (options = {}) {
    this.port = options.port || defaults.port
    this.serverUri = options.serverUri || defaults.serverUri

    this.parsedUri = url.parse(this.serverUri)
    this.host = this.parsedUri.host
    this.hostname = this.parsedUri.hostname
    this.live = options.live
    this.root = options.root
    this.multiuser = options.multiuser
    this.webid = options.webid
  }

  /**
   * Factory method, returns an instance of `SolidHost`.
   *
   * @param [options={}] {Object} See `constructor()` docstring.
   *
   * @return {SolidHost}
   */
  static from (options = {}) {
    return new SolidHost(options)
  }

  /**
   * Composes and returns an account URI for a given username, in multi-user mode.
   * Usage:
   *
   *   ```
   *   // host.serverUri === 'https://example.com'
   *
   *   host.accountUriFor('alice')  // -> 'https://alice.example.com'
   *   ```
   *
   * @param accountName {string}
   *
   * @throws {TypeError} If no accountName given, or if serverUri not initialized
   * @return {string}
   */
  accountUriFor (accountName) {
    if (!accountName) {
      throw TypeError('Cannot construct uri for blank account name')
    }
    if (!this.parsedUri) {
      throw TypeError('Cannot construct account, host not initialized with serverUri')
    }
    return this.parsedUri.protocol + '//' + accountName + '.' + this.host
  }

  /**
   * Determines whether the given user is allowed to restore a session
   * from the given origin.
   *
   * @param userId {?string}
   * @param origin {?string}
   * @return {boolean}
   */
  allowsSessionFor (userId, origin, trustedOrigins) {
    // Allow no user or an empty origin
    if (!userId || !origin) return true
    // Allow the server and subdomains
    const originHost = getHostName(origin)
    const serverHost = getHostName(this.serverUri)
    if (originHost === serverHost) return true
    if (originHost.endsWith('.' + serverHost)) return true
    // Allow the user's own domain
    const userHost = getHostName(userId)
    if (originHost === userHost) return true
    if (trustedOrigins.includes(origin)) return true
    return false
  }

  /**
   * Returns the /authorize endpoint URL object (used in login requests, etc).
   *
   * @return {URL}
   */
  get authEndpoint () {
    const authUrl = url.resolve(this.serverUri, '/authorize')
    return url.parse(authUrl)
  }

  /**
   * Returns a cookie domain, based on the current host's serverUri.
   *
   * @return {string|null}
   */
  get cookieDomain () {
    let cookieDomain = null

    if (this.hostname.split('.').length > 1) {
      // For single-level domains like 'localhost', do not set the cookie domain
      // See section on 'domain' attribute at https://curl.haxx.se/rfc/cookie_spec.html
      cookieDomain = '.' + this.hostname
    }

    return cookieDomain
  }
}

function getHostName (url) {
  const match = url.match(/^\w+:\/*([^/]+)/)
  return match ? match[1] : ''
}

module.exports = SolidHost
