module View.Payment.Table
  ( view
  , In(..)
  , Out(..)
  ) where

import qualified Data.List               as L
import qualified Data.Map                as M
import qualified Data.Maybe              as Maybe
import           Data.Text               (Text)
import qualified Data.Text               as T
import           Reflex.Dom              (Dynamic, Event, MonadWidget)
import qualified Reflex.Dom              as R

import           Common.Model            (Category (..), Currency, Payment (..),
                                          PaymentCategory (..), SavedPayment,
                                          User (..), UserId)
import qualified Common.Model            as CM
import qualified Common.Msg              as Msg
import qualified Common.View.Format      as Format

import qualified Component.ConfirmDialog as ConfirmDialog
import qualified Component.Table         as Table
import qualified Util.Ajax               as Ajax
import qualified Util.Either             as EitherUtil
import qualified View.Payment.Form       as Form

data In t = In
  { _in_users             :: [User]
  , _in_currentUser       :: UserId
  , _in_categories        :: [Category]
  , _in_currency          :: Currency
  , _in_payments          :: [Payment]
  , _in_paymentCategories :: [PaymentCategory]
  }

data Out t = Out
  { _out_add    :: Event t SavedPayment
  , _out_edit   :: Event t SavedPayment
  , _out_delete :: Event t Payment
  }

view :: forall t m. MonadWidget t m => In t -> m (Out t)
view input = do

  table <- Table.view $ Table.In
    { Table._in_headerLabel = headerLabel
    , Table._in_rows = reverse . L.sortOn _payment_date $ _in_payments input
    , Table._in_cell =
      cell
        (_in_users input)
        (_in_categories input)
        (_in_paymentCategories input)
        (_in_currency input)
    , Table._in_cloneModal = \payment ->
      Form.view $ Form.In
        { Form._in_categories = _in_categories input
        , Form._in_paymentCategories = _in_paymentCategories input
        , Form._in_operation = Form.Clone payment
        }
    , Table._in_editModal = \payment ->
      Form.view $ Form.In
        { Form._in_categories = _in_categories input
        , Form._in_paymentCategories = _in_paymentCategories input
        , Form._in_operation = Form.Edit payment
        }
    , Table._in_deleteModal = \payment ->
      ConfirmDialog.view $ ConfirmDialog.In
        { ConfirmDialog._in_header  = Msg.get Msg.Payment_DeleteConfirm
        , ConfirmDialog._in_confirm = \e -> do
          res <- Ajax.delete
            (R.constDyn $ T.concat ["/api/payment/", T.pack . show $ _payment_id payment])
            e
          return $ payment <$ R.fmapMaybe EitherUtil.eitherToMaybe res
        }
    , Table._in_isOwner = (== (_in_currentUser input)) . _payment_user
    }

  return $ Out
    { _out_add = Table._out_add table
    , _out_edit = Table._out_edit table
    , _out_delete = Table._out_delete table
    }

data Header
  = NameHeader
  | CostHeader
  | UserHeader
  | CategoryHeader
  | DateHeader
  deriving (Eq, Show, Bounded, Enum)

headerLabel :: Header -> Text
headerLabel NameHeader     = Msg.get Msg.Payment_Name
headerLabel CostHeader     = Msg.get Msg.Payment_Cost
headerLabel UserHeader     = Msg.get Msg.Payment_User
headerLabel CategoryHeader = Msg.get Msg.Payment_Category
headerLabel DateHeader     = Msg.get Msg.Payment_Date

cell
  :: forall t m. MonadWidget t m
  => [User]
  -> [Category]
  -> [PaymentCategory]
  -> Currency
  -> Header
  -> Payment
  -> m ()
cell users categories paymentCategories currency header payment =
  case header of
    NameHeader ->
      R.text $ _payment_name payment

    CostHeader ->
      R.text . Format.price currency . _payment_cost $ payment

    UserHeader ->
      R.text . Maybe.fromMaybe "" . fmap _user_name $ CM.findUser (_payment_user payment) users

    CategoryHeader ->
      let
        category =
          findCategory categories paymentCategories (_payment_name payment)

        attrs =
          case category of
            Just c ->
              M.fromList
                [ ("class", "tag")
                , ("style", T.concat [ "background-color: ", _category_color c ])
                ]

            Nothing ->
              M.singleton "display" "none"
      in
        R.elAttr "span" attrs $
          R.text $
            Maybe.fromMaybe "" (_category_name <$> category)

    DateHeader ->
      do
        R.elClass "span" "shortDate" $
          R.text . Format.shortDay . _payment_date $ payment

        R.elClass "span" "longDate" $
          R.text . Format.longDay . _payment_date $ payment

findCategory :: [Category] -> [PaymentCategory] -> Text -> Maybe Category
findCategory categories paymentCategories paymentName = do
  paymentCategory <- L.find
    ((== T.toLower paymentName) . _paymentCategory_name)
    paymentCategories
  L.find ((== (_paymentCategory_category paymentCategory)) . _category_id) categories