from flask import render_template, redirect, request, send_file, url_for, flash, current_app
from flask_login import login_required, login_manager, login_user, logout_user, current_user
from sqlalchemy.sql.functions import user
from app.forms import SignupForm, LoginForm, ApplicationForm
from app.models import TravelApplication, User
from werkzeug.utils import secure_filename
from app import app, db, bcrypt
from functools import wraps
import datetime
import uuid
import os

# Current date
current_date = datetime.datetime.now()

path = os.getcwd()

VALID_ID_FOLDER = os.path.join(path, 'app/static/uploads/valid_ids')
RAPID_TEST_FOLDER = os.path.join(path, 'app/static/uploads/rapid_tests')

# Recursively create the paths, if the preceding path doesn't exist
if not os.path.exists(os.path.join(path, 'app/static/uploads')):
	os.makedirs(VALID_ID_FOLDER)
	os.makedirs(RAPID_TEST_FOLDER)

# File upload folders
app.config['VALID_ID_FOLDER'] = RAPID_TEST_FOLDER
app.config['RAPID_TEST_FOLDER'] = VALID_ID_FOLDER

# User roles login_required decorator
def login_required(user_type='default'):
	def wrapper(fn):
		@wraps(fn)
		def decorated_view(*args, **kwargs):
			if not current_user.is_authenticated:
				# If user is not authenticated...
				# redirect to login and use the url endpoint to the 'next' parameter
				return redirect(url_for('login', next=request.endpoint))
			if current_user.user_type != user_type and user_type != 'default':
				return redirect(url_for('login', next=request.endpoint))
			return fn(*args, **kwargs)
		return decorated_view
	return wrapper

# Redirect to the endpoint of the next parameter...
# if it exists and is valid, else redirect to a fallback
def redirect_dest(fallback):
	dest = request.args.get('next')
	try:
		dest_url = url_for(dest)
	except:
		return redirect(fallback)
	return redirect(dest_url)

@app.route('/', methods=['GET', 'POST'])
def login():
	# If user is already authenticated redirect to designated page
	if current_user.is_authenticated and current_user.user_type == 'admin':
		return redirect_dest(fallback=url_for('admin_dashboard'))
	elif current_user.is_authenticated and current_user.user_type == 'user':
		return redirect_dest(fallback=url_for('user_dashboard'))

	form = LoginForm()
	if form.validate_on_submit():
		user = User.query.filter_by(email=form.email.data).first()
		if user and bcrypt.check_password_hash(user.password, form.password.data) and user.user_type == 'admin':
			login_user(user, remember=form.remember.data)
			return redirect_dest(fallback=url_for('admin_dashboard'))
		elif user and bcrypt.check_password_hash(user.password, form.password.data) and user.user_type == 'user':
			login_user(user, remember=form.remember.data)
			return redirect_dest(fallback=url_for('user_dashboard'))
		else:
			flash('Login failed! Your email or password is incorrect.', 'red')
	return render_template('pages/auth/login.html', form=form)

@app.route('/logout')
def logout():
	logout_user()
	return redirect(url_for('login'))

@app.route('/signup', methods=['GET', 'POST'])
def signup():
	# If user is already authenticated redirect to designated page
	if current_user.is_authenticated and current_user.user_type == 'admin':
		return redirect_dest(fallback=url_for('admin_dashboard'))
	elif current_user.is_authenticated and current_user.user_type == 'user':
		return redirect_dest(fallback=url_for('user_dashboard'))
		
	form = SignupForm()
	if form.validate_on_submit():
		user_type = 'user'
		hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
		user = User(email=form.email.data, password=hashed_password, user_type=user_type)

		db.session.add(user)
		db.session.commit()

		flash('Success! Your account has been created.', 'green')
		return redirect(url_for('login'))
	return render_template('pages/auth/signup.html', form=form)



@app.route('/admin/dashboard')
@login_required(user_type='admin')
def admin_dashboard():
	# Total no. of travel applications
	total = TravelApplication.query.all()
	# All approved requests
	approved = TravelApplication.query.filter(TravelApplication.status == 'approved').all()
	# All pending requests
	pending = TravelApplication.query.filter(TravelApplication.status == 'pending').all()
	# All cancelled requests
	cancelled = TravelApplication.query.filter(TravelApplication.status == 'cancelled').all()

	return render_template('pages/admin/dashboard.html', current_date=current_date, total=total, approved=approved, pending=pending, cancelled=cancelled)

@app.route('/admin/travel-records')
@login_required(user_type='admin')
def admin_travel_records():
	records = TravelApplication.query.all()
	return render_template('pages/admin/travel_records.html', current_date=current_date, records=records)

@app.route('/admin/travel-records/delete/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='admin')
def admin_delete_record(id):
	if request.method == 'POST':
		record_id = TravelApplication.query.get_or_404(id)
		# Delete uploaded files
		os.remove(os.path.join(app.config['VALID_ID_FOLDER'], record_id.attachment_1))
		os.remove(os.path.join(app.config['RAPID_TEST_FOLDER'], record_id.attachment_2))

		db.session.delete(record_id)
		db.session.commit()

		flash('Success! Travel application has been deleted.', 'green')
		return redirect(url_for('admin_travel_records'))
	return redirect(url_for('admin_travel_records'))

@app.route('/admin/travel-records/view/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='admin')
def admin_view_record(id):
	record = TravelApplication.query.filter_by(id=id)
	return render_template('pages/admin/view_travel_record.html', current_date=current_date, record=record)

@app.route('/admin/travel-records/approved/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='admin')
def approve(id):
	if request.method == 'POST':
		record_id = TravelApplication.query.get_or_404(id)

		if record_id.status == 'pending':
			# Update approval status to 'approved'
			record_id.status = request.form['status']
			db.session.commit()
		else:
			flash('Failed! Approval status is already set and cannot be modified.', 'red')
			return redirect(url_for('admin_view_record', id=id))

		flash('Success! Travel application has been approved.', 'green')
		return redirect(url_for('admin_view_record', id=id))
	return redirect(url_for('admin_travel_records'))

@app.route('/admin/travel-records/cancelled/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='admin')
def cancel(id):
	if request.method == 'POST':
		record_id = TravelApplication.query.get_or_404(id)

		if record_id.status == 'pending':
			# Update approval status to 'cancelled'
			record_id.status = request.form['status']
			db.session.commit()
		else:
			flash('Failed! Approval status is already set and cannot be modified.', 'red')
			return redirect(url_for('admin_view_record', id=id))

		flash('Success! Travel application has been cancelled.', 'green')
		return redirect(url_for('admin_view_record', id=id))
	return redirect(url_for('admin_travel_records'))



@app.route('/user/dashboard')
@login_required(user_type='user')
def user_dashboard():
	# Total no. of travel applications
	total = TravelApplication.query.filter(TravelApplication.user_id == current_user.id).all()
	# All approved requests
	approved = TravelApplication.query.filter(TravelApplication.user_id == current_user.id).filter(TravelApplication.status == 'approved').all()
	# All pending requests
	pending = TravelApplication.query.filter(TravelApplication.user_id == current_user.id).filter(TravelApplication.status == 'pending').all()
	# All cancelled requests
	cancelled = TravelApplication.query.filter(TravelApplication.user_id == current_user.id).filter(TravelApplication.status == 'cancelled').all()
	
	return render_template('pages/user/dashboard.html', current_date=current_date, total=total, approved=approved, pending=pending, cancelled=cancelled)

@app.route('/user/application-form', methods=['GET', 'POST'])
@login_required(user_type='user')
def user_application_form():
	form = ApplicationForm()
	if form.validate_on_submit():
		user_id = request.form['user_id']

		valid_id = form.attachment_1.data
		# Rename the uploaded file
		valid_id_filename, valid_id_extension = os.path.splitext(str(valid_id.filename))
		valid_id_filename = uuid.uuid4().hex
		attachment_1 = secure_filename(str(valid_id_filename + valid_id_extension))
		# then save it to the designated folder
		valid_id.save(os.path.join(app.config['VALID_ID_FOLDER'], attachment_1))

		rapid_test = form.attachment_2.data
		# Rename the uploaded file
		rapid_test_filename, rapid_test_extension = os.path.splitext(str(rapid_test.filename))
		rapid_test_filename = uuid.uuid4().hex
		attachment_2 = secure_filename(str(rapid_test_filename + rapid_test_extension))
		# then save it to the designated folder
		rapid_test.save(os.path.join(app.config['RAPID_TEST_FOLDER'], attachment_2))

		# Default approval status
		status = 'pending'

		travel_application = TravelApplication(user_id=user_id, firstname=form.firstname.data, middlename=form.middlename.data, lastname=form.lastname.data, sex=form.sex.data, dob=form.dob.data, address=form.address.data, purpose_of_travel=form.purpose_of_travel.data, details_of_travel=form.details_of_travel.data, origin_address_1=form.origin_address_1.data, origin_barangay=form.origin_barangay.data, origin_city=form.origin_city.data, origin_province=form.origin_province.data, destination_address_1=form.destination_address_1.data, destination_barangay=form.destination_barangay.data, destination_city=form.destination_city.data, destination_province=form.destination_province.data, vehicle_type=form.vehicle_type.data, plate_number=form.plate_number.data, classification=form.classification.data, date_of_arrival=form.date_of_arrival.data, attachment_1=attachment_1, attachment_2=attachment_2, status=status)

		db.session.add(travel_application)
		db.session.commit()

		flash('Success! Travel application has been submitted.', 'green')
		return redirect(url_for('user_application_form'))
	return render_template('pages/user/application_form.html', current_date=current_date, form=form)

@app.route('/user/travel-records')
@login_required(user_type='user')
def user_travel_records():
	records = TravelApplication.query.filter(TravelApplication.user_id == current_user.id)
	return render_template('pages/user/travel_records.html', current_date=current_date, records=records)

@app.route('/user/travel-records/update/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='user')
def user_update_record(id):
	record = TravelApplication.query.filter(TravelApplication.user_id == current_user.id).filter_by(id=id)
	record_id = TravelApplication.query.get_or_404(id)

	# If status is already approved redirect to user_travel_records
	if record_id.status == 'approved':
		flash('Failed! Travel application is already approved you cannot update it anymore.', 'red')
		return redirect(url_for('user_travel_records'))

	if request.method == 'POST':
		record_id.firstname = request.form['firstname']
		record_id.middlename = request.form['middlename']
		record_id.lastname = request.form['lastname']
		record_id.sex = request.form['sex']
		record_id.dob = request.form['dob']
		record_id.address = request.form['address']

		record_id.purpose_of_travel = request.form['purpose']
		record_id.details_of_travel = request.form['details']

		record_id.origin_address_1 = request.form['origin_address_1']
		record_id.origin_barangay = request.form['origin_barangay']
		record_id.origin_city = request.form['origin_city']
		record_id.origin_province = request.form['origin_province']

		record_id.destination_address_1 = request.form['destination_address_1']
		record_id.destination_barangay = request.form['destination_barangay']
		record_id.destination_city = request.form['destination_city']
		record_id.destination_province = request.form['destination_province']

		record_id.vehicle_type = request.form['vehicle_type']
		record_id.plate_number = request.form['plate_number']

		record_id.classification = request.form['classification']
		record_id.date_of_arrival = request.form['date_of_arrival']

		db.session.commit()

		flash('Success! Travel application has been updated.', 'green')
		return redirect(url_for('user_travel_records'))
	return render_template('pages/user/update_travel_record.html', current_date=current_date, record=record)

@app.route('/user/travel-records/delete/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='user')
def user_delete_record(id):
	if request.method == 'POST':
		record_id = TravelApplication.query.get_or_404(id)

		# if status is pending or cancelled delete the record and uploaded files
		if record_id.status == 'pending' or record_id.status == 'cancelled':
			# Delete uploaded files
			os.remove(os.path.join(app.config['VALID_ID_FOLDER'], record_id.attachment_1))
			os.remove(os.path.join(app.config['RAPID_TEST_FOLDER'], record_id.attachment_2))

			db.session.delete(record_id)
			db.session.commit()
		else:
			flash('Failed! Travel application cannot be deleted.', 'red')
			return redirect(url_for('user_travel_records'))

		flash('Success! Travel application has been deleted.', 'green')
		return redirect(url_for('user_travel_records'))
	return redirect(url_for('user_travel_records'))

@app.route('/user/travel-records/view/<int:id>', methods=['GET', 'POST'])
@login_required(user_type='user')
def user_view_record(id):
	record = TravelApplication.query.filter(TravelApplication.user_id == current_user.id).filter_by(id=id)
	return render_template('pages/user/view_travel_record.html', current_date=current_date, record=record)

@app.route('/download/valid_id/<filename>')
def download_attachment_1(filename):
	path = os.path.join(app.config['VALID_ID_FOLDER'], filename)
	return send_file(path, as_attachment=True)

@app.route('/download/rapid_test/<filename>')
def download_attachment_2(filename):
	path = os.path.join(app.config['RAPID_TEST_FOLDER'], filename)
	return send_file(path, as_attachment=True)