from pyramid.config import Configurator
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from datetime import datetime, date
from dateutil import tz
from pyramid.renderers import JSON
from bson.objectid import ObjectId
from .pagination import Pagination


try:
    # for python 2
    from urlparse import urlparse
except ImportError:
    # for python 3
    from urllib.parse import urlparse

from pymongo import MongoClient

from_zone = tz.tzutc()
to_zone = tz.tzlocal()


def format_datetime(inpDate, format='medium'):
    inpDate = inpDate.replace(tzinfo=from_zone)
    localDate = inpDate.astimezone(to_zone)
    if format == 'long':
        format = "%A, %B %d %Y at %I:%M:%S %p"
    elif format == 'medium':
        format = "%a, %b %d %Y %I:%M:%S %p"
    elif format == 'short':
        format = "%m/%d/%Y %I:%M:%S %p"
    return localDate.strftime(format)


def format_dateString(inpDate, format='medium'):
    iDate = datetime.strptime(inpDate, '%Y-%m-%d')
    if format == 'long':
        format = "%A, %B %d %Y"
    elif format == 'medium':
        format = "%a, %b %d %Y"
    elif format == 'short':
        format = "%m/%d/%Y"
    return iDate.strftime(format)


def format_date(inpDate, format='medium'):
    if format == 'long':
        format = "%A, %B %d %Y"
    elif format == 'medium':
        format = "%a, %b %d %Y"
    elif format == 'short':
        format = "%m/%d/%Y"
    return inpDate.strftime(format)


def roundDigits(inpValue, digits=2):
    return round(inpValue, digits)


# JSON RENDERERS
def datetime_adapter(obj, request):
    return obj.strftime("%Y-%m-%d %H:%M:%S.%fZ")


def objectId_adapter(obj, request):
    return str(obj)


def date_adapter(obj, request):
    return obj.strftime("%Y-%m-%d")


def pagination_adapter(obj, request):
    p = {
        'page': obj.page,
        'per_page': obj.per_page,
        'total_count': obj.total_count,
    }
    return p


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    authentication_policy = AuthTktAuthenticationPolicy('H3nryP7mp')
    authorization_policy = ACLAuthorizationPolicy()
    config = Configurator(settings=settings,
                          authentication_policy=authentication_policy,
                          authorization_policy=authorization_policy)
    config.include('pyramid_jinja2')
    config.commit()  # this is needed or you will get None back on the next line
    jinja2_env = config.get_jinja2_environment()
    jinja2_env.filters['datetime'] = format_datetime
    jinja2_env.filters['date'] = format_date
    jinja2_env.filters['datestring'] = format_dateString

    db_url = urlparse(settings['mongo_uri'])
    config.registry.db = MongoClient(
        host=db_url.hostname,
        port=db_url.port,
    )

    config.registry.db.poc.users.update_one({"username": "admin"}, {"$set": {"username": "admin", "password": "l3tm31n"}}, upsert=True)

    def add_db(request):
        db = config.registry.db[db_url.path[1:]]
        if db_url.username and db_url.password:
            db.authenticate(db_url.username, db_url.password)
        return db

    config.add_request_method(add_db, 'db', reify=True)
    config.add_static_view('static', 'static', cache_max_age=3600)

    # CUSTOM JSON RENDERER
    prettyjson = JSON(indent=4)
    prettyjson.add_adapter(datetime, datetime_adapter)
    prettyjson.add_adapter(date, date_adapter)
    prettyjson.add_adapter(ObjectId, objectId_adapter)
    prettyjson.add_adapter(Pagination, pagination_adapter)
    config.add_renderer('prettyjson', prettyjson)

    # SHARED ROUTES
    config.add_route('home', '/')
    config.add_route('json_snapshot', '/json')


    config.add_route('cards', '/cards')
    config.add_route('json_cards', '/json/cards')

    config.add_route('cards_date', '/cards?date={cards_date}')
    config.add_route('json_cards_date', '/json/cards?date={cards_date}')
    config.add_route('cards_page', '/cards?date={cards_date}&page={page_num}')
    config.add_route('json_cards_page', '/json/cards?date={cards_date}&page={page_num}')

    config.add_route('card_single', "/card/view/{stroke_number}")
    config.add_route('json_card_single', "/json/card/view/{stroke_number}")

    config.add_route('values_all', "/values")
    config.add_route('json_values_all', "/json/values")

    config.add_route('values_tag', "/values/tag/{tagname}")

    config.add_route('values_time', '/values/time/{time}')
    config.add_route('json_values_time', '/json/values/time/{time}')

    config.add_route('gaugeoff_all', '/gaugeoff')
    config.add_route('json_gaugeoff_all', '/json/gaugeoff')

    config.add_route('fluidshots_all', '/fluidshots')
    config.add_route('json_fluidshots_all', '/json/fluidshots')

    config.add_route('welltests_all', '/welltests')
    config.add_route('json_welltests_all', '/json/welltests')

    config.add_route('runstatus_page', '/runstatus/{page_num}')
    config.add_route('runstatus', '/runstatus')
    config.add_route('json_runstatus_page', '/json/runstatus/{page_num}')
    config.add_route('json_runstatus', '/json/runstatus')

    config.add_route('json_config', '/json/config', factory='pocwww.security.UserLoginFactory')
    config.add_route('config', '/config', factory='pocwww.security.UserLoginFactory')

    config.add_route('json_config', '/json/setpoints', factory='pocwww.security.UserLoginFactory')
    config.add_route('config', '/setpoints', factory='pocwww.security.UserLoginFactory')

    config.add_route('admin', '/admin', factory='pocwww.security.UserLoginFactory')
    config.add_route('auth', '/sign/{action}')
    config.add_route('register', '/register', factory='pocwww.security.UserLoginFactory')

    # JSON-ONLY ROUTES
    config.add_route('json_lastcard', "/json/lastcard")
    config.add_route('json_runstatusnow', "/json/runstatusnow")

    config.add_route('json_valuesbetween_wparams', "/json/values/between/{startdt}/{enddt}")
    config.add_route('json_valuesbetween', "/json/values/between")
    config.add_route("json_valuesdaterange", "/json/values/daterange")

    config.add_route('json_singlevaluebetween_wparams', "/json/values/tag/{tagname}/between/{startdt}/{enddt}")
    config.add_route('json_singlevaluebetween', "/json/values/tag/{tagname}")
    config.add_route("json_singlevaluedaterange", "/json/values/tag/{tagname}/daterange")

    config.add_route("json_updateconfig", "/json/updateconfig", factory='pocwww.security.UserLoginFactory')
    config.add_route("json_shake", '/json/cmd/shake', factory='pocwww.security.UserLoginFactory')
    config.add_route("json_cmd", '/json/cmd/{action}', factory='pocwww.security.UserLoginFactory')

    config.add_route("json_update_poc_address", "/json/updatepocaddress", factory='pocwww.security.UserLoginFactory')

    config.add_route("json_users", "/json/users", factory='pocwww.security.UserLoginFactory')

    config.scan()
    return config.make_wsgi_app()
