import ExpoModulesCore

/// The `MapmapNav` Expo module: a thin JS-facing adapter over
/// `MapmapNavCore`. Every `AsyncFunction` matches a method on
/// `MapmapNavModule` in `src/MapmapNav.types.ts`; every event matches
/// `MapmapNavEvents`. Structured arguments cross as dictionaries and are
/// parsed inside the core.
public final class MapmapNavModule: Module {

  private lazy var core: MapmapNavCore = {
    // Weakly capture self so event emission never retains the module.
    MapmapNavCore(emit: { [weak self] name, body in
      self?.sendEvent(name, body)
    })
  }()

  public func definition() -> ModuleDefinition {
    Name("MapmapNav")

    Events("territoryProgress", "guidance", "voiceState", "bridgeError")

    // MARK: Lifecycle
    AsyncFunction("init") { (apiKey: String, gatewayBaseUrl: String?) in
      try await self.core.initialize(apiKey: apiKey, gatewayBaseUrl: gatewayBaseUrl)
    }

    // MARK: Territories
    AsyncFunction("listAvailableTerritories") { () -> [[String: Any]] in
      try await self.core.listAvailableTerritories()
    }
    AsyncFunction("listInstalledTerritories") { () -> [[String: Any]] in
      try await self.core.listInstalledTerritories()
    }
    AsyncFunction("installTerritory") { (territoryId: String) in
      try await self.core.installTerritory(territoryId)
    }
    AsyncFunction("removeTerritory") { (territoryId: String) in
      try await self.core.removeTerritory(territoryId)
    }
    AsyncFunction("getTerritoryStyle") { (territoryId: String, theme: String) -> String in
      try await self.core.getTerritoryStyle(territoryId, theme: theme)
    }

    // MARK: Search
    AsyncFunction("search") {
      (query: String, near: [String: Any]?, limit: Int?) -> [[String: Any]] in
      try await self.core.search(query: query, near: near, limit: limit)
    }

    // MARK: Routing
    AsyncFunction("computeRoute") { (request: [String: Any]) -> [String: Any] in
      try await self.core.computeRoute(request)
    }

    // MARK: Guidance
    AsyncFunction("startGuidance") { (options: [String: Any]) in
      try await self.core.startGuidance(options)
    }
    AsyncFunction("stopGuidance") { () in
      try await self.core.stopGuidance()
    }

    // MARK: Voice
    AsyncFunction("setVoiceMuted") { (muted: Bool) in
      try await self.core.setVoiceMuted(muted)
    }
    AsyncFunction("setVoiceVolume") { (volume: Double) in
      try await self.core.setVoiceVolume(volume)
    }
  }
}
