 import CatenaCore
 import LoggerAPI
 
-/** The SQL agent coordinates participation in a dist*/
+/** The SQL agent coordinates participation in a distributed blockchain-based database. */
 public class SQLAgent {
 	let node: Node<SQLLedger>
 	private var counters: [PublicKey: SQLTransaction.CounterType] = [:]

	/** Submit a transaction, after issue'ing a consecutive counter value to it and signing it with the private key
	provided. */
	public func submit(transaction: SQLTransaction, signWith key: PrivateKey) throws -> Bool {
        return try autoreleasepool { () -> Bool in
            try self.mutex.locked {
                if let previous = self.counters[transaction.invoker] {
                    Log.debug("[SQLAgent] last counter for \(transaction.invoker) was \(previous)")
                    transaction.counter = previous + SQLTransaction.CounterType(1)
                }
                else {
                    // Look up the counter value
                    try self.node.ledger.longest.withUnverifiedTransactions { chain in
                        if let previous = try chain.meta.users.counter(for: transaction.invoker) {
                            Log.debug("[SQLAgent] last counter for \(transaction.invoker) was \(previous) according to ledger")
                            transaction.counter = previous + SQLTransaction.CounterType(1)
                        }
                        else {
                            Log.debug("[SQLAgent] no previous counter for \(transaction.invoker)")
                            transaction.counter = SQLTransaction.CounterType(0)
                        }
                    }
                }

                Log.debug("[SQLAgent] using counter \(transaction.counter) for \(transaction.invoker)")
                self.counters[transaction.invoker] = transaction.counter
            }

            // Submit
            try transaction.sign(with: key)
            return try self.node.receive(transaction: transaction, from: nil)
        }
	}
}

private class SQLAPIEndpointCORS: RouterMiddleware {
    let allowCorsOrigin: String?
    
    init(allowOrigin: String?) {
        self.allowCorsOrigin = allowOrigin
    }
    
    public func handle(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
        if let ac = self.allowCorsOrigin {
            response.headers.append("Access-Control-Allow-Origin", value: ac)
            response.headers.append("Access-Control-Allow-Methods", value: "GET, POST, OPTIONS")
            response.headers.append("Content-Type", value: "application/json")
            response.headers.append("Access-Control-Allow-Headers", value: "Content-Type, Accept")
            if request.method == .options {
                _ = response.send(status: .OK)
            }
            else {
                next()
            }
        }
        else {
            next()
        }
    }
}

public class SQLAPIEndpoint {
	let agent: SQLAgent
    
    /** Set 'allowCorsOrigin' to the domain name(s) from which requests may be made. Set to nil to
     disallow any requests from other domains, or set to '*' to allow from any domain. */
    public init(agent: SQLAgent, router: Router, allowCorsOrigin: String?) {
		self.agent = agent

		// API used by the web client

		router.post("/api/*", middleware: mw)
		router.get("/api", handler: self.handleIndex)
		router.get("/api/counter/:hash", handler: self.handleGetCounter)
		router.post("/api/query", handler: self.handleQuery)

		// Debug APIs
		router.get("/debug/block/:hash", handler: self.handleGetBlock)
