module View.Payment.Table
  ( widget
  , TableIn(..)
  , TableOut(..)
  ) 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           Prelude             hiding (init)
import           Reflex.Dom          (Dynamic, Event, MonadWidget)
import qualified Reflex.Dom          as R

import           Common.Model        (Category (..), Frequency (Punctual),
                                      Init (..), Payment (..),
                                      PaymentCategory (..), SavedPayment,
                                      User (..))
import qualified Common.Model        as CM
import qualified Common.Msg          as Msg
import qualified Common.View.Format  as Format
import           Component           (ButtonIn (..), ButtonOut (..))
import qualified Component           as Component
import qualified Component.Modal     as Modal
import qualified View.Payment.Clone  as Clone
import qualified View.Payment.Delete as Delete
import qualified View.Payment.Edit   as Edit

import qualified Icon
import qualified Util.Reflex         as ReflexUtil

-- TODO: remove
import           Debug.Trace         (trace)

data TableIn t = TableIn
  { _tableIn_init              :: Init
  , _tableIn_currentPage       :: Dynamic t Int
  , _tableIn_payments          :: Dynamic t [Payment]
  , _tableIn_perPage           :: Int
  , _tableIn_paymentCategories :: Dynamic t [PaymentCategory]
  , _tableIn_categories        :: [Category]
  }

data TableOut t = TableOut
  { _tableOut_addPayment    :: Event t SavedPayment
  , _tableOut_editPayment   :: Event t SavedPayment
  , _tableOut_deletePayment :: Event t Payment
  }

widget :: forall t m. MonadWidget t m => TableIn t -> m (TableOut t)
widget tableIn = do
  R.divClass "table" $ do

    (addPayment, editPayment, deletePayment) <- R.divClass "lines" $ do
      R.divClass "header" $ do
        R.divClass "cell name" $ R.text $ Msg.get Msg.Payment_Name
        R.divClass "cell cost" $ R.text $ Msg.get Msg.Payment_Cost
        R.divClass "cell user" $ R.text $ Msg.get Msg.Payment_User
        R.divClass "cell category" $ R.text $ Msg.get Msg.Payment_Category
        R.divClass "cell date" $ R.text $ Msg.get Msg.Payment_Date
        R.divClass "cell" $ R.blank
        R.divClass "cell" $ R.blank
        R.divClass "cell" $ R.blank

      result <-
        (R.simpleList paymentRange (paymentRow init paymentCategories))

      return $
        ( R.switch . R.current . fmap (R.leftmost . map (\(a, _, _) -> a)) $ result
        , R.switch . R.current . fmap (R.leftmost . map (\(_, b, _) -> b)) $ result
        , R.switch . R.current . fmap (R.leftmost . map (\(_, _, c) -> c)) $ result
        )

    ReflexUtil.divClassVisibleIf (null <$> payments) "emptyTableMsg" $
      R.text $ Msg.get Msg.Payment_Empty

    return $ TableOut
      { _tableOut_addPayment = addPayment
      , _tableOut_editPayment = editPayment
      , _tableOut_deletePayment = deletePayment
      }

  where
    init = _tableIn_init tableIn
    currentPage = _tableIn_currentPage tableIn
    payments = _tableIn_payments tableIn
    paymentRange = getPaymentRange (_tableIn_perPage tableIn) <$> payments <*> currentPage
    paymentCategories = _tableIn_paymentCategories tableIn

getPaymentRange :: Int -> [Payment] -> Int -> [Payment]
getPaymentRange perPage payments currentPage =
  take perPage
    . drop ((currentPage - 1) * perPage)
    . reverse
    . L.sortOn _payment_date
    $ payments

paymentRow
  :: forall t m. MonadWidget t m
  => Init
  -> Dynamic t [PaymentCategory]
  -> Dynamic t Payment
  -> m (Event t SavedPayment, Event t SavedPayment, Event t Payment)
paymentRow init paymentCategories payment =
  R.divClass "row" $ do

    R.divClass "cell name" $
      R.dynText $ fmap _payment_name payment

    R.divClass "cell cost" $
      R.dynText $ fmap (Format.price (_init_currency init) . _payment_cost) payment

    let user = R.ffor payment (\p ->
          CM.findUser (_payment_user p) (_init_users init))

    R.divClass "cell user" $
      R.dynText $ flip fmap user $ \mbUser -> case mbUser of
        Just u -> _user_name u
        _      -> ""

    let category = do
          p <- payment
          pcs <- paymentCategories
          return $ findCategory (_init_categories init) pcs (_payment_name p)

    R.divClass "cell category" $ do

      let attrs = flip fmap category $ \maybeCategory -> case maybeCategory of
            Just c -> M.fromList
              [ ("class", "tag")
              , ("style", T.concat [ "background-color: ", _category_color c ])
              ]
            Nothing -> M.singleton "display" "none"

      R.elDynAttr "span" attrs $
        R.dynText $ R.ffor category $ \case
          Just c -> _category_name c
          _      -> ""

    R.divClass "cell date" $ do
      R.elClass "span" "shortDate" . R.dynText . fmap (Format.shortDay . _payment_date) $ payment
      R.elClass "span" "longDate" . R.dynText . fmap (Format.longDay . _payment_date) $ payment

    let categoryId = (Maybe.fromMaybe (-1) . fmap _category_id) <$> category

    clonePayment <-
      R.divClass "cell button" $
        _buttonOut_clic <$> (Component.button $
          Component.defaultButtonIn Icon.clone)

    paymentCloned <-
      Modal.view $ Modal.Input
        { Modal._input_show    = clonePayment
        , Modal._input_content =
            Clone.view $ Clone.Input
              { Clone._input_show = clonePayment
              , Clone._input_categories = _init_categories init
              , Clone._input_paymentCategories = paymentCategories
              , Clone._input_payment = payment
              , Clone._input_category = categoryId
              }
        }

    let isFromCurrentUser =
          R.ffor
            payment
            (\p -> _payment_user p == _init_currentUser init)

    editPayment <-
      R.divClass "cell button" $
        ReflexUtil.divVisibleIf isFromCurrentUser $
          _buttonOut_clic <$> (Component.button $
            Component.defaultButtonIn Icon.edit)

    paymentEdited <-
      Modal.view $ Modal.Input
        { Modal._input_show    = editPayment
        , Modal._input_content =
            Edit.view $ Edit.Input
              { Edit._input_show = editPayment
              , Edit._input_categories = _init_categories init
              , Edit._input_paymentCategories = paymentCategories
              , Edit._input_payment = payment
              , Edit._input_category = categoryId
              }
        }

    deletePayment <-
      R.divClass "cell button" $
        ReflexUtil.divVisibleIf isFromCurrentUser $
          _buttonOut_clic <$> (Component.button $
            (Component.defaultButtonIn Icon.delete)
              { _buttonIn_class = R.constDyn "deletePayment"
              })

    paymentDeleted <-
      Modal.view $ Modal.Input
        { Modal._input_show    = deletePayment
        , Modal._input_content =
            Delete.view $ Delete.Input
              { Delete._input_payment = payment
              }
        }

    return $ (paymentCloned, paymentEdited, paymentDeleted)

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