content: {-
   Copyright 2022-23, Juspay India Pvt Ltd
  
   This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License
  
   as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program
  
   is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  
   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of
  
   the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
  -}
  module Beckn.OnDemand.Transformer.Search where
  
  import qualified Beckn.OnDemand.Utils.Common
  import qualified Beckn.OnDemand.Utils.Search
  import qualified Beckn.Types.Core.Taxi.Common.Address
  import qualified BecknV2.OnDemand.Tags as Tags
  import qualified BecknV2.OnDemand.Types
  import qualified BecknV2.OnDemand.Types as Spec
  -- import qualified BecknV2.OnDemand.Utils.Common as Utils
  import qualified BecknV2.OnDemand.Utils.Common
  import qualified BecknV2.Utils as Utils
  import qualified Data.Text
  import qualified Data.Text as T
  import qualified Domain.Action.Beckn.Search
  import qualified Domain.Action.Internal.Estimate as DBppEstimate
  import EulerHS.Prelude hiding (id)
  import Kernel.External.Encryption
  import qualified Kernel.External.Maps
  import qualified Kernel.Types.App
  import qualified Kernel.Types.Common
  import qualified Kernel.Types.Registry.Subscriber
  import Kernel.Utils.Common (decodeFromText, fromMaybeM, type (:::))
  import Kernel.Utils.Logging (logDebug)
  import Tools.Error
  
  buildSearchReq :: (Kernel.Types.App.HasFlowEnv m r '["_version" ::: Data.Text.Text], EncFlow m r) => Data.Text.Text -> Kernel.Types.Registry.Subscriber.Subscriber -> BecknV2.OnDemand.Types.SearchReqMessage -> BecknV2.OnDemand.Types.Context -> m Domain.Action.Beckn.Search.DSearchReq
  buildSearchReq messageId subscriber req context = do
    now <- Kernel.Types.Common.getCurrentTime
    let bapId_ = subscriber.subscriber_id
        bapUri_ = subscriber.subscriber_url
        customerLanguage_ = Beckn.OnDemand.Utils.Search.buildCustomerLanguage req
        customerNammaTags_ = Beckn.OnDemand.Utils.Search.buildCustomerNammaTags req
        isDashboardRequest_ = Beckn.OnDemand.Utils.Search.checkIfDashboardSearch req
        device_ = Nothing
        disabilityTag_ = Beckn.OnDemand.Utils.Search.buildDisabilityTag req
        isReallocationEnabled_ = Beckn.OnDemand.Utils.Search.getIsReallocationEnabled req
        isMeterRideSearch = Beckn.OnDemand.Utils.Search.getIsMeterRideSearch req
        fareParametersInRateCard_ = Beckn.OnDemand.Utils.Search.fareParametersInRateCard req
        messageId_ = messageId
        routeDistance_ = Beckn.OnDemand.Utils.Search.getDistance req
        routeDuration_ = Beckn.OnDemand.Utils.Search.getDuration req
        returnTime_ = Beckn.OnDemand.Utils.Search.getReturnTime req
        isRoundTrip_ = Beckn.OnDemand.Utils.Search.getRoundTrip req
        routePoints_ = Beckn.OnDemand.Utils.Search.buildRoutePoints req
        multipleRoutes = Beckn.OnDemand.Utils.Search.buildMultipleRoutesTag req
        driverIdentifier = Beckn.OnDemand.Utils.Search.getDriverIdentifier req
        pickupTime_ = fromMaybe now $ Beckn.OnDemand.Utils.Search.getPickUpTime req
        isMultimodalSearch = Beckn.OnDemand.Utils.Search.getIsMultimodalSearch req
        isReserveRide = getIsReserveRide req
        reserveRideEstimate = getReserveRideEstimate req isReserveRide
    bapCountry_ <- Beckn.OnDemand.Utils.Common.getContextCountry context
    customerPhoneNum_ <- getPhoneNumberFromTag $ Beckn.OnDemand.Utils.Search.buildCustomerPhoneNumber req
    dropAddrress_ <- Beckn.OnDemand.Utils.Search.getDropOffLocation req & tfAddress
    dropLocation_ <- tfLatLong `mapM` Beckn.OnDemand.Utils.Search.getDropOffLocationGps req
    stopLocations <- Beckn.OnDemand.Utils.Search.getIntermediateStopLocations req
    stops <- buildLocation `mapM` stopLocations
    pickupAddress_ <- Beckn.OnDemand.Utils.Search.getPickUpLocation req >>= (tfAddress . Just)
    pickupLocation_ <- Beckn.OnDemand.Utils.Search.getPickUpLocationGps req >>= tfLatLong
    transactionId_ <- BecknV2.OnDemand.Utils.Common.getTransactionId context
    logDebug $ "Phone Number at bap side is: " <> show (Beckn.OnDemand.Utils.Search.buildCustomerPhoneNumber req)
    logDebug $ "Phone Number at bap side is: " <> show customerPhoneNum_
    pure $
      Domain.Action.Beckn.Search.DSearchReq
        { bapCountry = bapCountry_,
          bapId = bapId_,
          bapUri = bapUri_,
          customerLanguage = customerLanguage_,
          customerNammaTags = customerNammaTags_,
          customerPhoneNum = customerPhoneNum_,
          isDashboardRequest = fromMaybe False isDashboardRequest_,
          roundTrip = fromMaybe False isRoundTrip_,
          returnTime = returnTime_,
          device = device_,
          disabilityTag = disabilityTag_,
          dropAddrress = dropAddrress_,
          dropLocation = dropLocation_,
          isReallocationEnabled = isReallocationEnabled_,
          fareParametersInRateCard = fareParametersInRateCard_,
          messageId = messageId_,
          pickupAddress = pickupAddress_,
          pickupLocation = pickupLocation_,
          pickupTime = pickupTime_,
          routeDistance = routeDistance_,
          routeDuration = routeDuration_,
          routePoints = routePoints_,
          transactionId = transactionId_,
          stops,
          isReserveRide = isReserveRide,
          mbAdditonalChargeCategories = Nothing,
          ..
        }
  
  -- [door, building, street, area, city, state, areaCode, country]
  tfAddress :: (Kernel.Types.App.HasFlowEnv m r '["_version" ::: Data.Text.Text]) => Maybe BecknV2.OnDemand.Types.Location -> m (Maybe Beckn.Types.Core.Taxi.Common.Address.Address)
  tfAddress Nothing = pure Nothing
  tfAddress (Just location) = do
    fullAddress <- location.locationAddress & fromMaybeM (InvalidRequest $ "Location address is missing, location:-" <> show location)
    returnData <- Beckn.OnDemand.Utils.Common.buildAddressFromText fullAddress
    let allNothing = BecknV2.OnDemand.Utils.Common.allNothing returnData
    if allNothing
      then do
        pure Nothing
      else do
        pure $ Just returnData
  
  tfLatLong :: (Kernel.Types.App.HasFlowEnv m r '["_version" ::: Data.Text.Text]) => Data.Text.Text -> m Kernel.External.Maps.LatLong
  tfLatLong locationGps = do
    lat_ <- Beckn.OnDemand.Utils.Common.parseLatLong locationGps
    lon_ <- Beckn.OnDemand.Utils.Common.parseLatLong locationGps
    pure $ Kernel.External.Maps.LatLong {lat = Kernel.External.Maps.lat lat_, lon = Kernel.External.Maps.lon lon_}
  
  buildLocation :: (Kernel.Types.App.HasFlowEnv m r '["_version" ::: Data.Text.Text]) => Spec.Location -> m Domain.Action.Beckn.Search.DSearchReqLocation
  buildLocation location = do
    address <- tfAddress (Just location)
    locationGpsText <- location.locationGps & fromMaybeM (InvalidRequest "Missing Pickup Location")
    latLong <- tfLatLong locationGpsText
    pure $
      Domain.Action.Beckn.Search.DSearchReqLocation
        { address,
          gps = latLong
        }
  
  getIsReserveRide :: Spec.SearchReqMessage -> Maybe Bool
  getIsReserveRide req = do
    intent <- req.searchReqMessageIntent
    fulfillment <- intent.intentFulfillment
    tags <- fulfillment.fulfillmentTags
    readMaybe . T.unpack =<< Utils.getTagV2 Tags.SEARCH_REQUEST_INFO Tags.RESERVED_RIDE_TAG (Just tags)
  
  getReserveRideEstimate :: Spec.SearchReqMessage -> Maybe Bool -> Maybe DBppEstimate.BppEstimate
  getReserveRideEstimate req isReserveRide = do
    if isReserveRide == Just True
      then do
        intent <- req.searchReqMessageIntent
        fulfillment <- intent.intentFulfillment
        tags <- fulfillment.fulfillmentTags
        decodeFromText =<< Utils.getTagV2 Tags.SEARCH_REQUEST_INFO Tags.RESERVED_PRICING_TAG (Just tags)
      else Nothing
  
  getPhoneNumberFromTag :: (Kernel.Types.App.HasFlowEnv m r '["_version" ::: Data.Text.Text], EncFlow m r) => Maybe Text -> m (Maybe Text)
  getPhoneNumberFromTag customerPhoneNum_ = do
    case customerPhoneNum_ of
      Just phoneNumber ->
        mapM decrypt $ textToEncryptedHashed phoneNumber
      Nothing -> do
        return Nothing
  