module Happstack.Auth.Core.ProfileParts where

import Control.Applicative (Alternative(..))
import Data.Acid           (AcidState)
import Data.Acid.Advanced  (update', query')
import           Data.Set  (Set)
import qualified Data.Set  as Set
import Happstack.Server
import Happstack.Auth.Core.Auth
import Happstack.Auth.Core.ProfileURL
import Happstack.Auth.Core.Profile
import Web.Routes
import Web.Routes.Happstack

-- * ProfileURL stuff

-- can we pick an AuthId with only the information in the Auth stuff? Or should that be a profile action ?

pickAuthId :: (Happstack m, Alternative m) => AcidState AuthState -> m (Either (Set AuthId) AuthId)
pickAuthId authStateH =
    do (Just authToken) <- getAuthToken authStateH -- FIXME: Just
       case tokenAuthId authToken of
         (Just authId) -> return (Right authId)
         Nothing ->
             do authIds <- case tokenAuthMethod authToken of
                             (AuthIdentifier identifier) -> query' authStateH (IdentifierAuthIds identifier)
                             (AuthFacebook   facebookId) -> query' authStateH (FacebookAuthIds facebookId)
                case Set.size authIds of
                  0 -> do authId <- update' authStateH (NewAuthMethod (tokenAuthMethod authToken))
                          update' authStateH (UpdateAuthToken (authToken { tokenAuthId = Just authId }))
                          return (Right authId)
                  1 -> do let aid = head $ Set.toList authIds
                          update' authStateH (UpdateAuthToken (authToken { tokenAuthId = Just aid }))
                          return (Right aid)
                  n -> return (Left authIds)

setAuthIdPage :: (Alternative m, Happstack m) => AcidState AuthState -> AuthId -> m Bool
setAuthIdPage authStateH authId =
    do mAuthToken <- getAuthToken authStateH
       case mAuthToken of
         Nothing -> undefined -- FIXME
         (Just authToken) ->
             do authIds <- case tokenAuthMethod authToken of
                             (AuthIdentifier identifier) -> query' authStateH (IdentifierAuthIds identifier)
                             (AuthFacebook   facebookId) -> query' authStateH (FacebookAuthIds facebookId)
                if Set.member authId authIds
                   then do update' authStateH (UpdateAuthToken (authToken { tokenAuthId = Just authId }))
                           return True
                   else return False

data PickProfile
    = Picked UserId
    | PickPersonality (Set Profile)
    | PickAuthId      (Set AuthId)

pickProfile :: (Happstack m, Alternative m) => AcidState AuthState -> AcidState ProfileState -> m PickProfile
pickProfile authStateH profileStateH =
    do eAid <- pickAuthId authStateH
       case eAid of
         (Right aid) ->
             do mUid <- query' profileStateH (AuthIdUserId aid)
                case mUid of
                  Nothing ->
                      do profiles <- query' profileStateH (AuthIdProfiles aid)
                         case Set.size profiles of
                           0 -> do uid <- update' profileStateH (CreateNewProfile (Set.singleton aid))
                                   update' profileStateH (SetAuthIdUserId aid uid)
                                   return (Picked uid)
--                                   seeOther onLoginURL (toResponse onLoginURL)
                           1 -> do let profile = head $ Set.toList profiles
                                   update' profileStateH (SetAuthIdUserId aid (userId profile))
                                   return (Picked (userId profile))
                           n -> do return (PickPersonality profiles)
                  (Just uid) ->
                      return (Picked uid)
         (Left aids) -> return (PickAuthId aids)
