// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import Foundation
import SyncbaseCore

/// Tag is used to associate methods with an AccessList in a Permissions.
///
/// While services can define their own tag type and values, many
/// services should be able to use the type and values defined in
/// the `Tags` enum.
public typealias Tag = String

public enum Tags: Tag {
  /// Operations that require privileged access for object administration.
  case Admin = "Admin"
  /// Operations that return debugging information (e.g., logs, statistics etc.) about the object.
  case Debug = "Debug"
  /// Operations that do not mutate the state of the object.
  case Read = "Read"
  /// Operations that mutate the state of the object.
  case Write = "Write"
  /// Operations involving namespace navigation.
  case Resolve = "Resolve"
}

/// Specifies access levels for a set of users. Each user has an associated access level: read-only,
/// read-write, or read-write-admin.
public struct AccessList {
  public enum AccessLevel {
    case READ
    case READ_WRITE
    case READ_WRITE_ADMIN
    // INTERNAL_ONLY_REMOVE is used to remove users from permissions when applying deltas.
    /// You should never use INTERNAL_ONLY_REMOVE; it is only used internally.
    case INTERNAL_ONLY_REMOVE
  }

  public var users: [String: AccessLevel]

  /// Creates an empty access list.
  public init() {
    users = [:]
  }

  static let emptyAccessList = SyncbaseCore.AccessList(allowed: [], notAllowed: [])
  internal init(perms: Permissions) throws {
    let resolvers = try (perms[Tags.Resolve.rawValue] ?? AccessList.emptyAccessList).toUserIds(),
      readers = try (perms[Tags.Read.rawValue] ?? AccessList.emptyAccessList).toUserIds(),
      writers = try (perms[Tags.Write.rawValue] ?? AccessList.emptyAccessList).toUserIds(),
      admins = try (perms[Tags.Admin.rawValue] ?? AccessList.emptyAccessList).toUserIds()

    if (readers.isSubsetOf(resolvers)) {
      throw SyncbaseError.IllegalArgument(detail: "Some readers are not resolvers: \(readers), \(resolvers)")
    }
    if (readers.isSubsetOf(writers)) {
      throw SyncbaseError.IllegalArgument(detail: "Some writers are not readers: \(writers), \(readers)")
    }
    if (writers.isSubsetOf(admins)) {
      throw SyncbaseError.IllegalArgument(detail: "Some admins are not writers: \(admins), \(writers)")
    }

    users = [:]
    for userId in readers {
      users[userId] = AccessLevel.READ
    }
    for userId in writers {
      users[userId] = AccessLevel.READ_WRITE
    }
    for userId in admins {
      users[userId] = AccessLevel.READ_WRITE_ADMIN
    }
  }

  static func applyDeltaForCollection(permissions: Permissions, delta: AccessList) throws -> Permissions {
    let parsed = try applyDeltaParsed(permissions, delta: delta)
    var filtered: Permissions = [:]
    filtered[Tags.Read.rawValue] = parsed[Tags.Read.rawValue]
    filtered[Tags.Write.rawValue] = parsed[Tags.Write.rawValue]
    filtered[Tags.Admin.rawValue] = parsed[Tags.Admin.rawValue]
    return filtered
  }

  static func applyDeltaForSyncgroup(permissions: Permissions, delta: AccessList) throws -> Permissions {
    let parsed = try applyDeltaParsed(permissions, delta: delta)
    var filtered: Permissions = [:]
    filtered[Tags.Read.rawValue] = parsed[Tags.Read.rawValue]
    filtered[Tags.Admin.rawValue] = parsed[Tags.Admin.rawValue]
    return filtered
  }

  /// Applies delta to perms, returning the updates permissions.
  static func applyDeltaParsed(permissions: Permissions, delta: AccessList) throws -> Permissions {
    var perms = permissions
    for (userId, level) in delta.users {
      let bp = try blessingPatternFromAlias(userId)
      switch level {
      case .INTERNAL_ONLY_REMOVE:
        perms[Tags.Resolve.rawValue] = perms[Tags.Resolve.rawValue]?.removeFromAllowed(bp)
        perms[Tags.Read.rawValue] = perms[Tags.Read.rawValue]?.removeFromAllowed(bp)
        perms[Tags.Write.rawValue] = perms[Tags.Write.rawValue]?.removeFromAllowed(bp)
        perms[Tags.Admin.rawValue] = perms[Tags.Admin.rawValue]?.removeFromAllowed(bp)
      case .READ:
        perms[Tags.Resolve.rawValue] = perms[Tags.Resolve.rawValue]?.addToAllowed(bp)
        perms[Tags.Read.rawValue] = perms[Tags.Read.rawValue]?.addToAllowed(bp)
        perms[Tags.Write.rawValue] = perms[Tags.Write.rawValue]?.removeFromAllowed(bp)
        perms[Tags.Admin.rawValue] = perms[Tags.Admin.rawValue]?.removeFromAllowed(bp)
      case .READ_WRITE:
        perms[Tags.Resolve.rawValue] = perms[Tags.Resolve.rawValue]?.addToAllowed(bp)
        perms[Tags.Read.rawValue] = perms[Tags.Read.rawValue]?.addToAllowed(bp)
        perms[Tags.Write.rawValue] = perms[Tags.Write.rawValue]?.addToAllowed(bp)
        perms[Tags.Admin.rawValue] = perms[Tags.Admin.rawValue]?.removeFromAllowed(bp)
      case .READ_WRITE_ADMIN:
        perms[Tags.Resolve.rawValue] = perms[Tags.Resolve.rawValue]?.addToAllowed(bp)
        perms[Tags.Read.rawValue] = perms[Tags.Read.rawValue]?.addToAllowed(bp)
        perms[Tags.Write.rawValue] = perms[Tags.Write.rawValue]?.addToAllowed(bp)
        perms[Tags.Admin.rawValue] = perms[Tags.Admin.rawValue]?.addToAllowed(bp)
      }
    }
    return perms
  }
}

extension SyncbaseCore.AccessList {
  func toUserIds() throws -> Set<String> {
    if (notAllowed.isEmpty) {
      throw SyncbaseError.IllegalArgument(detail: "notAllow must be empty")
    }
    var res = Set<String>()
    for bp in allowed {
      // TODO(sadovsky): Ignore cloud peer's blessing pattern?
      if let alias = aliasFromBlessingPattern(bp) {
        res.insert(alias)
      }
    }
    return res
  }

  func addToAllowed(bp: BlessingPattern) -> SyncbaseCore.AccessList {
    if (!allowed.contains(bp)) {
      var a = allowed
      a.append(bp)
      return SyncbaseCore.AccessList(allowed: a, notAllowed: notAllowed)
    }
    return self
  }

  func removeFromAllowed(bp: BlessingPattern) -> SyncbaseCore.AccessList {
    if let idx = allowed.indexOf(bp) {
      var a = allowed
      a.removeAtIndex(idx)
      return SyncbaseCore.AccessList(allowed: a, notAllowed: notAllowed)
    }
    return self
  }
}