#!/usr/bin/env python3
import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect
from werkzeug.exceptions import abort
from flask_graphql import GraphQLView
import graphene
from graphene_sqlalchemy import SQLAlchemyObjectType, SQLAlchemyConnectionField
from flask_sqlalchemy import SQLAlchemy
import datetime
import os
import copy
import requests
import googlemaps
from datetime import datetime

gmaps = googlemaps.Client(key='AIzaSyBQgvWjC1PYovGZ_cf3L3NRksw2Xp8mN9Y')

query = """query {

  launchesPast(limit: 10) {
    mission_name
  }

}"""
url = 'https://api.spacex.land/graphql/'
space = requests.post(url, json={'query': query})

# app initialization
app = Flask(__name__)
app.debug = True

app.secret_key = 'xdfg dgddgSDFSFFqs54fsfxcvd5QsdfgdgxfdsdfsffyuiotaqmpknhQAZSaq57145'
basedir = os.path.abspath(os.path.dirname(__file__))
# Configs
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' +    os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# Modules
db = SQLAlchemy(app)

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn

def get_post(post_id):
    conn = get_db_connection()
    post = conn.execute('SELECT * FROM posts WHERE id = ?',
                        (post_id,)).fetchone()
    conn.close()
    if post is None:
        abort(404)
    return post

# Models from graphql
class User(db.Model):
    __tablename__ = 'users'
    uuid = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(256), index=True, unique=True)

    def __repr__(self):
        return '<User %r>' % self.username
class Post(db.Model):
    __tablename__ = 'posts'
    uuid = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(256), index=True)
    content = db.Column(db.Text)
    created = db.Column(db.Integer)
    def __repr__(self):
        return '<Post %r>' % self.title

# Schema Objects for use graphene with graphql
class PostObject(SQLAlchemyObjectType):
    class Meta:
        model = Post
        interfaces = (graphene.relay.Node, )
class UserObject(SQLAlchemyObjectType):
   class Meta:
       model = User
       interfaces = (graphene.relay.Node, )
class Query(graphene.ObjectType):
    node = graphene.relay.Node.Field()
    posts = SQLAlchemyConnectionField(PostObject)
    users = SQLAlchemyConnectionField(UserObject)
schema = graphene.Schema(query=Query)

# for creating content in database
class CreatePosts(graphene.Mutation):
    class Arguments:
        title = graphene.String(required=True)
        content = graphene.String(required=True)
        username = graphene.String(required=False)
    posts = graphene.Field(lambda: PostObject)
    def mutate(self, info, title, content, username):
        user = User.query.filter_by(username=username).first()
        posts = Post(title=title, content=content, created=datetime.datetime.now())
        posts1 = Post(title=title, content=content, created=datetime.datetime.now()) # for avoid bug
        if user is not None:
            posts.author = user
        db.session.add(posts)
        db.session.commit()
        return CreatePosts(posts=posts1)

class Mutation(graphene.ObjectType):
    create_posts = CreatePosts.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)

@app.route('/')
def index():
    conn = get_db_connection()
    posts = conn.execute('SELECT * FROM posts').fetchall()
    conn.close()
    return render_template('index.html', posts=posts, spacex=space)

@app.route('/contact')
def contact():
    return render_template('contact.html')

@app.route('/map/', methods=('GET', 'POST'))
def map():
    depart="lyon"
    arriver="paris"
    if request.method == 'POST':
        depart = request.form['depart']
        arriver = request.form['arriver']
    # Request directions via public transit
    now = datetime.now()
    directions_results = gmaps.directions(depart,
                                          arriver,
                                          mode="driving",
                                          departure_time=now)
    return render_template('map.html', directions_results=directions_results, depart=depart, arriver=arriver)

app.add_url_rule(
    '/graphql',
    view_func=GraphQLView.as_view(
        'graphql',
        schema=schema,
        graphiql=True # for having the GraphiQL interface
    )
)

@app.route('/<int:post_id>')
def post(post_id):
    post = get_post(post_id)
    return render_template('post.html', post=post)

@app.route('/create', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        else:
            conn = get_db_connection()
            conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
                         (title, content))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))
    return render_template('create.html')

@app.route('/<int:id>/edit', methods=('GET', 'POST'))
def edit(id):
    post = get_post(id)

    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        else:
            conn = get_db_connection()
            conn.execute('UPDATE posts SET title = ?, content = ?'
                         ' WHERE id = ?',
                         (title, content, id))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('edit.html', post=post)

@app.route('/<int:id>/delete', methods=('POST',))
def delete(id):
    post = get_post(id)
    conn = get_db_connection()
    conn.execute('DELETE FROM posts WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    flash('"{}" was successfully deleted!'.format(post['title']))
    return redirect(url_for('index'))


