import ACL from '../acl-checker.mjs'
// import debug from '../debug.mjs'

export default function allow (mode) {
  return async function allowHandler (req, res, next) {
    const ldp = req.app.locals.ldp || {}
    if (!ldp.webid) {
      return next()
    }

    // Set up URL to filesystem mapping
    const rootUrl = ldp.resourceMapper.resolveUrl(req.hostname)

    // Determine the actual path of the request
    // (This is used as an ugly hack to check the ACL status of other resources.)
    let resourcePath = res && res.locals && res.locals.path
      ? res.locals.path
      : req.path

    // Check whether the resource exists
    let stat
    try {
      const ret = await ldp.exists(req.hostname, resourcePath)
      stat = ret.stream
    } catch (err) {
      stat = null
    }

    // Ensure directories always end in a slash
    if (!resourcePath.endsWith('/') && stat && stat.isDirectory()) {
      resourcePath += '/'
    }

    const trustedOrigins = [ldp.resourceMapper.resolveUrl(req.hostname)].concat(ldp.trustedOrigins)
    if (ldp.multiuser) {
      trustedOrigins.push(ldp.serverUri)
    }
    // Obtain and store the ACL of the requested resource
    const resourceUrl = rootUrl + resourcePath
    // Ensure the user has the required permission
    const userId = req.session.userId
    try {
      req.acl = ACL.createFromLDPAndRequest(resourceUrl, ldp, req)

      // if (resourceUrl.endsWith('.acl')) mode = 'Control'
      const isAllowed = await req.acl.can(userId, mode, req.method, stat)
      if (isAllowed) {
        return next()
      }
    } catch (error) { next(error) }
    if (mode === 'Read' && (resourcePath === '' || resourcePath === '/')) {
      // This is a hack to make NSS check the ACL for representation that is served for root (if any)
      // See https://github.com/solid/node-solid-server/issues/1063 for more info
      const representationUrl = `${rootUrl}/index.html`
      let representationPath
      try {
        representationPath = await ldp.resourceMapper.mapUrlToFile({ url: representationUrl })
      } catch (err) {
      }

      // We ONLY want to do this when the HTML representation exists
      if (representationPath) {
        req.acl = ACL.createFromLDPAndRequest(representationUrl, ldp, req)
        const representationIsAllowed = await req.acl.can(userId, mode)
        if (representationIsAllowed) {
          return next()
        }
      }
    }

    // check if user is owner. Check isOwner from /.meta
    try {
      if (resourceUrl.endsWith('.acl') && (await ldp.isOwner(userId, req.hostname))) return next()
    } catch (err) {}
    const error = req.authError || await req.acl.getError(userId, mode)
    // debug.handlers(`ALLOW -- ${mode} access denied to ${userId || '(none)'}: ${error.status} - ${error.message}`)
    next(error)
  }
}
