text: import Foundation
  import UIKit
  import Display
  import LegacyComponents
  import TelegramCore
  import SyncCore
  import Postbox
  import TelegramPresentationData
  import AccountContext
  import ShareController
  import LegacyUI
  import OpenInExternalAppUI
  import AppBundle
  import LocationResources
  
  private func generateClearIcon(color: UIColor) -> UIImage? {
      return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: color)
  }
  
  func makeLegacyPeer(_ peer: Peer) -> AnyObject? {
      if let user = peer as? TelegramUser {
          let legacyUser = TGUser()
          legacyUser.uid = user.id.id
          legacyUser.firstName = user.firstName
          legacyUser.lastName = user.lastName
          if let representation = smallestImageRepresentation(user.photo) {
              legacyUser.photoUrlSmall = legacyImageLocationUri(resource: representation.resource)
          }
          return legacyUser
      } else if let channel = peer as? TelegramChannel {
          let legacyConversation = TGConversation()
          legacyConversation.conversationId = Int64(channel.id.id)
          legacyConversation.chatTitle = channel.title
          if let representation = smallestImageRepresentation(channel.photo) {
              legacyConversation.chatPhotoSmall = legacyImageLocationUri(resource: representation.resource)
          }
          return legacyConversation
      } else {
          return nil
      }
  }
  
  private func makeLegacyMessage(_ message: Message) -> TGMessage {
      let result = TGMessage()
      result.mid = message.id.id
      result.date = Double(message.timestamp)
      if message.flags.contains(.Failed) {
          result.deliveryState = TGMessageDeliveryStateFailed
      } else if message.flags.contains(.Sending) {
          result.deliveryState = TGMessageDeliveryStatePending
      } else {
          result.deliveryState = TGMessageDeliveryStateDelivered
      }
      
      for attribute in message.attributes {
          if let attribute = attribute as? EditedMessageAttribute {
              result.editDate = Double(attribute.date)
          }
      }
      
      var media: [Any] = []
      for m in message.media {
          if let mapMedia = m as? TelegramMediaMap {
              let legacyLocation = TGLocationMediaAttachment()
              legacyLocation.latitude = mapMedia.latitude
              legacyLocation.longitude = mapMedia.longitude
              if let venue = mapMedia.venue {
                  legacyLocation.venue = TGVenueAttachment(title: venue.title, address: venue.address, provider: venue.provider, venueId: venue.id, type: venue.type)
              }
              if let liveBroadcastingTimeout = mapMedia.liveBroadcastingTimeout {
                  legacyLocation.period = liveBroadcastingTimeout
              }
              
              media.append(legacyLocation)
          }
      }
      if !media.isEmpty {
          result.mediaAttachments = media
      }
      
      return result
  }
  
  private func legacyRemainingTime(message: TGMessage) -> SSignal {
      var liveBroadcastingTimeoutValue: Int32?
      if let mediaAttachments = message.mediaAttachments {
          for media in mediaAttachments {
              if let m = media as? TGLocationMediaAttachment, m.period != 0 {
                  liveBroadcastingTimeoutValue = m.period
              }
          }
      }
      guard let liveBroadcastingTimeout = liveBroadcastingTimeoutValue else {
          return SSignal.fail(nil)
      }
      
      if message.deliveryState != TGMessageDeliveryStateDelivered {
          return SSignal.single(liveBroadcastingTimeout as NSNumber)
      }
      
      let remainingTime = SSignal.`defer`({
          let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
          let remainingTime = max(0, Int32(message.date) + liveBroadcastingTimeout - currentTime)
          var signal = SSignal.single(remainingTime as NSNumber)
          if remainingTime == 0 {
              signal = signal?.then(SSignal.fail(nil))
          }
          return signal
      })!
      
      return (remainingTime.then(SSignal.complete().delay(5.0, on: SQueue.main()))).restart().`catch`({ _ in
          return SSignal.complete()
      })
  }
  
  private func telegramMap(for location: TGLocationMediaAttachment) -> TelegramMediaMap {
      let mapVenue: MapVenue?
      if let venue = location.venue {
          mapVenue = MapVenue(title: venue.title ?? "", address: venue.address ?? "", provider: venue.provider ?? "", id: venue.venueId ?? "", type: venue.type ?? "")
      } else {
          mapVenue = nil
      }
      return TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, geoPlace: nil, venue: mapVenue, liveBroadcastingTimeout: nil)
  }
  
  func legacyLocationPalette(from theme: PresentationTheme) -> TGLocationPallete {
      let listTheme = theme.list
      let searchTheme = theme.rootController.navigationSearchBar
      return TGLocationPallete(backgroundColor: listTheme.plainBackgroundColor, selectionColor: listTheme.itemHighlightedBackgroundColor, separatorColor: listTheme.itemPlainSeparatorColor, textColor: listTheme.itemPrimaryTextColor, secondaryTextColor: listTheme.itemSecondaryTextColor, accentColor: listTheme.itemAccentColor, destructiveColor: listTheme.itemDestructiveColor, locationColor: UIColor(rgb: 0x008df2), liveLocationColor: UIColor(rgb: 0xff6464), iconColor: searchTheme.backgroundColor, sectionHeaderBackgroundColor: theme.chatList.sectionHeaderFillColor, sectionHeaderTextColor: theme.chatList.sectionHeaderTextColor, searchBarPallete: TGSearchBarPallete(dark: theme.overallDarkAppearance, backgroundColor: searchTheme.backgroundColor, highContrastBackgroundColor: searchTheme.backgroundColor, textColor: searchTheme.inputTextColor, placeholderColor: searchTheme.inputPlaceholderTextColor, clearIcon: generateClearIcon(color: theme.rootController.navigationSearchBar.inputClearButtonColor), barBackgroundColor: searchTheme.backgroundColor, barSeparatorColor: searchTheme.separatorColor, plainBackgroundColor: searchTheme.backgroundColor, accentColor: searchTheme.accentColor, accentContrastColor: searchTheme.backgroundColor, menuBackgroundColor: searchTheme.backgroundColor, segmentedControlBackgroundImage: nil, segmentedControlSelectedImage: nil, segmentedControlHighlightedImage: nil, segmentedControlDividerImage: nil), avatarPlaceholder: nil)
  }
  
  public func legacyLocationController(message: Message?, mapMedia: TelegramMediaMap, context: AccountContext, openPeer: @escaping (Peer) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, stopLiveLocation: @escaping () -> Void, openUrl: @escaping (String) -> Void) -> ViewController {
      let legacyLocation = TGLocationMediaAttachment()
      legacyLocation.latitude = mapMedia.latitude
      legacyLocation.longitude = mapMedia.longitude
      if let venue = mapMedia.venue {
          legacyLocation.venue = TGVenueAttachment(title: venue.title, address: venue.address, provider: venue.provider, venueId: venue.id, type: venue.type)
      }
      
      let presentationData = context.sharedContext.currentPresentationData.with { $0 }
      
      let legacyController = LegacyController(presentation: .navigation, theme: presentationData.theme, strings: presentationData.strings)
      legacyController.navigationPresentation = .modal
      let controller: TGLocationViewController
      
      let venueColor = mapMedia.venue?.type.flatMap { venueIconColor(type: $0) }
      if let message = message {
          let legacyMessage = makeLegacyMessage(message)
          let legacyAuthor: AnyObject? = message.author.flatMap(makeLegacyPeer)
          
          let updatedLocations = SSignal(generator: { subscriber in
              let disposable = topPeerActiveLiveLocationMessages(viewTracker: context.account.viewTracker, accountPeerId: context.account.peerId, peerId: message.id.peerId).start(next: { (_, messages) in
                  var result: [Any] = []
                  let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
                  loop: for message in messages {
                      var liveBroadcastingTimeout: Int32 = 0
                      
                      mediaLoop: for media in message.media {
                          if let map = media as? TelegramMediaMap, let timeout = map.liveBroadcastingTimeout  {
                              liveBroadcastingTimeout = timeout
                              break mediaLoop
                          }
                      }
                      
                      let legacyMessage = makeLegacyMessage(message)
                      guard let legacyAuthor = message.author.flatMap(makeLegacyPeer) else {
                          continue loop
                      }
                      let remainingTime = max(0, message.timestamp + liveBroadcastingTimeout - currentTime)
                      if legacyMessage.locationAttachment?.period != 0 {
                          let hasOwnSession = message.localTags.contains(.OutgoingLiveLocation)
                          var isOwn = false
                          if !message.flags.contains(.Incoming) {
                              isOwn = true
                          } else if let peer = message.peers[message.id.peerId] as? TelegramChannel {
                              isOwn = peer.hasPermission(.sendMessages)
                          }
                          
                          let liveLocation = TGLiveLocation(message: legacyMessage, peer: legacyAuthor, hasOwnSession: hasOwnSession, isOwnLocation: isOwn, isExpired: remainingTime == 0)!
                          result.append(liveLocation)
                      }
                  }
                  subscriber?.putNext(result)
              })
              
              return SBlockDisposable(block: {
                  disposable.dispose()
              })
          })!
          
          if let liveBroadcastingTimeout = mapMedia.liveBroadcastingTimeout {
              let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
              let remainingTime = max(0, message.timestamp + liveBroadcastingTimeout - currentTime)
              
              let messageLiveLocation = TGLiveLocation(message: legacyMessage, peer: legacyAuthor, hasOwnSession: false, isOwnLocation: false, isExpired: remainingTime == 0)!
              
              controller = TGLocationViewController(context: legacyController.context, liveLocation: messageLiveLocation)
              
              if remainingTime == 0 {
                  let freezeLocations: [Any] = [messageLiveLocation]
                  controller.setLiveLocationsSignal(.single(freezeLocations))
              } else {
                  controller.setLiveLocationsSignal(updatedLocations)
                  if message.flags.contains(.Incoming) {
                      context.account.viewTracker.updateSeenLiveLocationForMessageIds(messageIds: Set([message.id]))
                  }
              }
          } else {
              controller = TGLocationViewController(context: legacyController.context, message: legacyMessage, peer: legacyAuthor, color: venueColor)!
              controller.receivingPeer = message.peers[message.id.peerId].flatMap(makeLegacyPeer)
              controller.setLiveLocationsSignal(updatedLocations)
          }
          
          let namespacesWithEnabledLiveLocation: Set<PeerId.Namespace> = Set([
              Namespaces.Peer.CloudChannel,
              Namespaces.Peer.CloudGroup,
              Namespaces.Peer.CloudUser
              ])
          if namespacesWithEnabledLiveLocation.contains(message.id.peerId.namespace) {
              controller.allowLiveLocationSharing = true
          }
      } else {
          let attachment = TGLocationMediaAttachment()
          attachment.latitude = mapMedia.latitude
          attachment.longitude = mapMedia.longitude
          controller = TGLocationViewController(context: legacyController.context, locationAttachment: attachment, peer: nil, color: venueColor)
      }
      
      controller.remainingTimeForMessage = { message in
          return legacyRemainingTime(message: message!)
      }
      controller.liveLocationStarted = { [weak legacyController] coordinate, period in
          sendLiveLocation(coordinate, period)
          legacyController?.dismiss()
      }
      controller.liveLocationStopped = { [weak legacyController] in
          stopLiveLocation()
          legacyController?.dismiss()
      }
      
      let theme = (context.sharedContext.currentPresentationData.with { $0 }).theme
      controller.pallete = legacyLocationPalette(from: theme)
      
      controller.modalMode = true
      controller.presentActionsMenu = { [weak legacyController] legacyLocation, directions in
          if let strongLegacyController = legacyController, let location = legacyLocation {
              let map = telegramMap(for: location)
              
              let presentationData = context.sharedContext.currentPresentationData.with { $0 }
              let shareAction = OpenInControllerAction(title: presentationData.strings.Conversation_ContextMenuShare, action: {
                  strongLegacyController.present(ShareController(context: context, subject: .mapMedia(map), externalShare: true), in: .window(.root), with: nil)
              })
              
              strongLegacyController.present(OpenInActionSheetController(context: context, item: .location(location: map, withDirections: directions), additionalAction: !directions ? shareAction : nil, openUrl: openUrl), in: .window(.root), with: nil)
          }
      }
      
      controller.onViewDidAppear = { [weak controller] in
          if let strongController = controller {
              strongController.view.disablesInteractiveModalDismiss = true
              strongController.view.disablesInteractiveTransitionGestureRecognizer = true
              strongController.locationMapView.interactiveTransitionGestureRecognizerTest = { point -> Bool in
                  return point.x > 30.0
              }
          }
      }
      
      legacyController.navigationItem.title = controller.navigationItem.title
      controller.updateRightBarItem = { item, action, animated in
          if action {
              legacyController.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationShareIcon(theme), style: .plain, target: controller, action: #selector(controller.actionsButtonPressed))
          } else {
              legacyController.navigationItem.setRightBarButton(item, animated: animated)
          }
      }
      legacyController.bind(controller: controller)
      
      let presentationDisposable = context.sharedContext.presentationData.start(next: { [weak controller] presentationData in
          if let controller = controller  {
              controller.pallete = legacyLocationPalette(from: presentationData.theme)
          }
      })
      legacyController.disposables.add(presentationDisposable)
  
      return legacyController
  }
  