import elixir
import logging
from openid.consumer.consumer import Consumer
from openid.extensions.sreg import SRegRequest, SRegResponse
from openid.store.filestore import FileOpenIDStore
from openid.yadis.discover import DiscoveryFailure
from sqlalchemy.orm.exc import NoResultFound

from pylons import request, response, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect, redirect_to
from routes import url_for, request_config

from floof.lib.base import BaseController, render
import floof.lib.helpers as h
from floof.model.users import IdentityURL, User

log = logging.getLogger(__name__)

from floof.model import UserPage

class AccountController(BaseController):

    openid_store = FileOpenIDStore('/var/tmp')

    def login(self):
        c.bogus_identity_url = request.params.get('bogus_identity_url', None)
        return render('/account/login.mako')

    def login_begin(self):
        """Step one of logging in with OpenID; we redirect to the provider"""

        identity_url = request.params['identity_url']
        cons = Consumer(session=session, store=self.openid_store)
        try:
            auth_request = cons.begin(identity_url)
        except DiscoveryFailure:
            redirect_to(controller='account', action='login',
                        bogus_identity_url=identity_url)

        sreg_req = SRegRequest(optional=['nickname', 'email', 'dob', 'gender',
                                         'country', 'language', 'timezone'])
        auth_request.addExtension(sreg_req)

        host = request.headers['host']
        protocol = request_config().protocol
        return_url = url_for(host=host, controller='account', action='login_finish')
        new_url = auth_request.redirectURL(return_to=return_url,
                                           realm=protocol + '://' + host)
        redirect(new_url)

    def login_finish(self):
        """Step two of logging in; the OpenID provider redirects back here."""

        cons = Consumer(session=session, store=self.openid_store)
        host = request.headers['host']
        return_url = url_for(host=host, controller='account', action='login_finish')
        res = cons.complete(request.params, return_url)

        if res.status != 'success':
            return 'Error!  %s' % res.message

        try:
            # Grab an existing user record, if one exists
            q = User.query.filter(User.identity_urls.any(url=res.identity_url))
            user = q.one()
        except NoResultFound:
            # Unrecognized URL.  Redirect to a registration page to ask for a
            # nickname, etc.
            session['register:identity_url'] = res.identity_url

            # Try to pull a name out of the SReg response
            sreg_res = SRegResponse.fromSuccessResponse(res)
            if sreg_res and 'nickname' in sreg_res:
                session['register:nickname'] = sreg_res['nickname']

            session.save()
            redirect(url('register'))

        # Remember who's logged in, and we're good to go
        session['user_id'] = user.id
        session.save()
        h.flash(u'You are now logged in.')

        # XXX send me where I came from
        redirect('/')

    def logout(self):
        """Log user out."""

        if 'user_id' in session:
            del session['user_id']
            session.save()

        # XXX success message
        # XXX send me where I came from
        redirect('/')

    def register(self):
        """Logging in with an unrecognized identity URL redirects here."""

        c.identity_url = session['register:identity_url']
        c.nickname = session.get('register:nickname', None)
        # XXX hey, uh.  warn if this name is taken already.

        return render('/account/register.mako')

    def register_finish(self):
        """Complete a new-user registration.  Create the user and log in."""

        identity_url = session['register:identity_url']
        username = request.params.get('username', None)

        if not username:
            h.flash(u'Please enter a username.')
            return self.register()

        if User.query.filter_by(name=username).count():
            h.flash(u'This username is already taken.')
            return self.register()

        if not User.is_valid_name(username):
            h.flash(u'This username is not valid.')
            return self.register()

        if username in ['me']:
            h.flash(u'This username is reserved.')
            return self.register()

        # Create db records
        user = User(name=username, display_name=username)
        user.identity_urls.append(IdentityURL(url=identity_url))

        elixir.session.commit()

        # Log in
        session['user_id'] = user.id
        session.save()
        h.flash(u'You are now logged in.')

        # XXX send me where I came from
        redirect('/')
