import ExpoModulesCore
import CoreNFC

public class ExpoFelicaReaderModule: Module {
  var session: NfcSession?
  var semaphore: DispatchSemaphore?
  public func definition() -> ModuleDefinition {
    Name("ExpoFelicaReader")

    AsyncFunction("scan") { (promise: Promise) in
        session?.startSession()
        DispatchQueue.global(qos: .background).async {
            self.semaphore?.wait()
            promise.resolve(self.session?.message)
        }
    }
      
    OnCreate {
        semaphore = DispatchSemaphore(value: 0)
        session = NfcSession(semaphore: semaphore!)
    }
  }
}

class NfcSession: NSObject, NFCTagReaderSessionDelegate {
    var session: NFCTagReaderSession?
    let semaphore: DispatchSemaphore
    var message: String?

    init (semaphore: DispatchSemaphore) {
        self.semaphore = semaphore
    }
    
    func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
        print("tagReaderSessionDidBecomeActive")
    }
    
    func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
        print("Error: \(error.localizedDescription)")
        self.semaphore.signal()
        self.session = nil
    }
    
    func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
        let tag = tags.first!
        session.connect(to: tag) { error in
            if nil != error {
                session.invalidate(errorMessage: "Error!")
                self.semaphore.signal()
                return
            }
            guard case .feliCa(let feliCaTag) = tag else {
                session.invalidate(errorMessage: "This is not FeliCa!")
                self.semaphore.signal()
                return
            }
            let idm = feliCaTag.currentIDm.map { String(format: "%.2hhx", $0) }.joined()
            self.message = idm
            session.alertMessage = "Success!"
            session.invalidate()
            self.semaphore.signal()
        }
    }
    
    func startSession() {
        self.session = NFCTagReaderSession(pollingOption: [.iso14443, .iso15693, .iso18092], delegate: self, queue: nil)
        session?.alertMessage = "Touch your FeliCa!"
        session?.begin()
    }
}