from flask import Flask, make_response, redirect, request, jsonify, render_template, send_from_directory, send_file
import os
import dotenv
import requests
import datetime
import json
import render
import payments
import threading
import account
import qrcode
from io import BytesIO

app = Flask(__name__)
dotenv.load_dotenv()

# Exchange cache
exchange = {
    'timestamp': 0,
    'rate': 0
}

DEV = os.getenv('DEV', 'false').lower() in ['true', '1', 'yes']
tlds = ['australia','newzealand']

#Assets routes
@app.route('/assets/<path:path>')
def send_report(path):
    return send_from_directory('templates/assets', path)

@app.route('/sitemap')
@app.route('/sitemap.xml')
def sitemap():
    # Remove all .html from sitemap
    with open('templates/sitemap.xml') as file:
        sitemap = file.read()

    sitemap = sitemap.replace('.html', '')
    return make_response(sitemap, 200, {'Content-Type': 'application/xml'})

@app.route('/favicon.png')
def faviconPNG():
    return send_from_directory('templates/assets/img', 'favicon.png')

@app.route('/https.js')
@app.route('/handshake.js')
@app.route('/redirect.js')
def handshake():
    # return request.path
    return send_from_directory('templates/', request.path.split('/')[-1])

@app.route('/.well-known/wallets/<path:path>')
def wallet(path):
    return send_from_directory('templates/.well-known/wallets', path, mimetype='text/plain')
        


# Special routes
@app.route('/email')
def email():
    return redirect('mailto:hns@hns.au')

@app.route('/pins')
def pins():
    global exchange

    year = datetime.datetime.now().year
    # Get current exchange rate if not in cache
    if exchange['timestamp'] < datetime.datetime.now().timestamp() - 3600:
        response = requests.get('https://api.coingecko.com/api/v3/simple/price?ids=handshake&vs_currencies=usd')
        exchange['rate'] = response.json()['handshake']['usd']
        exchange['timestamp'] = datetime.datetime.now().timestamp()

    hns_45 = 45 / exchange['rate']
    hns_30 = 30 / exchange['rate']
    hns_50 = 50 / exchange['rate']

    # Round to the nearest 5 HNS and add commas
    hns_45 = int(hns_45 / 5) * 5
    hns_30 = int(hns_30 / 5) * 5
    hns_50 = int(hns_50 / 5) * 5

    hns_45 = "{:,}".format(hns_45)
    hns_30 = "{:,}".format(hns_30)
    hns_50 = "{:,}".format(hns_50)


    return render_template('pins.html', year=year, hns_45=hns_45, hns_30=hns_30,hns_50=hns_50)

@app.route('/pins/<path:path>')
def pins_redirect(path):
    global exchange

    if not os.path.isfile('templates/pins/'+path + ".html"):
        return render_template('404.html'), 404
    
    year = datetime.datetime.now().year
    # Get current exchange rate if not in cache
    if exchange['timestamp'] < datetime.datetime.now().timestamp() - 3600:
        response = requests.get('https://api.coingecko.com/api/v3/simple/price?ids=handshake&vs_currencies=usd')
        exchange['rate'] = response.json()['handshake']['usd']
        exchange['timestamp'] = datetime.datetime.now().timestamp()

    hns_45 = 45 / exchange['rate']
    hns_30 = 30 / exchange['rate']
    hns_50 = 50 / exchange['rate']

    # Round to the nearest 5 HNS and add commas
    hns_45 = int(hns_45 / 5) * 5
    hns_30 = int(hns_30 / 5) * 5
    hns_50 = int(hns_50 / 5) * 5

    hns_45 = "{:,}".format(hns_45)
    hns_30 = "{:,}".format(hns_30)
    hns_50 = "{:,}".format(hns_50)
    return render_template('pins/'+path + ".html", year=year, hns_45=hns_45, hns_30=hns_30,hns_50=hns_50)

@app.route('/pins/order/<path:path>')
def pins_order(path):
    if not os.path.isfile('templates/pins/'+path + ".html"):
        return render_template('404.html'), 404
    
    # Get cookies
    cookies = request.cookies
    if 'cart' in cookies:
        cart = cookies['cart']
    else:
        cart = '[]'

    cart = json.loads(cart)
    item = {
        'name': path,
        'quantity': 1
    }
    for i in range(len(cart)):
        if cart[i]['name'] == path:
            cart[i]['quantity'] += 1
            item = None
            break

    if item:
        cart.append(item)
    cart = json.dumps(cart)

    response = make_response(redirect('/cart'))
    response.set_cookie('cart', cart)
    return response

@app.route('/pins/update/<path:path>', methods=['POST'])
def pins_update(path):
    # Get cookies
    cookies = request.cookies
    if 'cart' in cookies:
        cart = cookies['cart']
    else:
        cart = '[]'

    cart = json.loads(cart)
    data = request.json
    for i in range(len(cart)):
        if cart[i]['name'] == path:
            cart[i]['quantity'] = data['quantity']
            break


    # Remove any item with less than 1 quantity
    cart = [item for item in cart if int(item['quantity']) > 0]
    cart = json.dumps(cart)

    response = make_response(jsonify({'status': 'ok'}))
    response.set_cookie('cart', cart)
    return response

@app.route('/cart')
def cart():
    year = datetime.datetime.now().year
    # Get cookies
    cookies = request.cookies
    if 'cart' in cookies:
        cart = cookies['cart']
    else:
        cart = '[]'

    promo_message = ''
    if 'promo' in cookies:
        promo = cookies['promo']
    else:
        promo = ''

    cart = json.loads(cart)
    cartHtml = render.cart(cart)

    if promo != '':
        promo = payments.getPromo(promo)
        if not promo:
            promo_message = 'Invalid promo code'
            promo = ''
        else:
            promo_message = f'Promo code {promo["id"]} applied'

        total_usd = render.total_usd(cart,promo)
        total_hns = render.total_hns(cart,promo)
        promoCode = ''
        if promo:
            promoCode = promo["id"]
    else:
        total_usd = render.total_usd(cart, False)
        total_hns = render.total_hns(cart, False)
        promoCode = ''

    return render_template('cart.html', year=year, cart=cartHtml, total_usd=total_usd, total_hns=total_hns,promo=promoCode, promo_message=promo_message)

@app.route('/cart/promo', methods=['POST'])
def cart_promo():
    data = request.form
    response = make_response(redirect('/cart'))
    response.set_cookie('promo', data['promo'])
    return response

@app.route('/payment')
def payment():
    year = datetime.datetime.now().year
    # Get cookies
    cookies = request.cookies
    if 'cart' in cookies:
        cart = cookies['cart']
    else:
        cart = '[]'

    if cart == '[]':
        return redirect('/cart')

    cart = json.loads(cart)
    cartHtml = render.cart_total(cart)

    if 'promo' in cookies:
        promo = cookies['promo']
        promo = payments.getPromo(promo)
        total_usd = render.total_usd(cart,promo)
        total_hns = render.total_hns(cart,promo)
    else:
        promo = ''
        total_usd = render.total_usd(cart, False)
        total_hns = render.total_hns(cart, False)

    

    return render_template('payment.html', year=year, cart=cartHtml, total_usd=total_usd, total_hns=total_hns)

@app.route('/payment', methods=['POST'])
def payment_post():
    # Get cookies
    cookies = request.cookies
    if 'cart' in cookies:
        cart = cookies['cart']
    else:
        cart = '[]'

    if cart == '[]':
        return redirect('/cart')

    cart = json.loads(cart)
    if 'promo' in cookies:
        promo = cookies['promo']
        promo = payments.getPromo(promo)
        total_usd = render.total_usd(cart,promo)
        total_hns = render.total_hns(cart,promo)
    else:
        promo = False
        total_usd = render.total_usd(cart, False)
        total_hns = render.total_hns(cart, False)


    data = request.form
    if 'email' in data:
        email = data['email']
    else:
        email = ''
    if 'mobile' in data:
        mobile = data['mobile']
    else:
        mobile = ''

    if 'address' in data:
        address = data['address']
    else:
        address = ''

    if 'country' in data:
        country = data['country']
    else:
        country = ''

    if 'name' in data:
        name = data['name']
    else:
        name = ''

    cartHtml = render.cart_total(cart)
    
    if email == '' or address == '' or name == '' or country == '' or mobile == '':
        return render_template('payment.html', error='Please fill all fields',
                               email=email, address=address, name=name, mobile=mobile, country=country,
            cart=cartHtml, total_usd=total_usd, total_hns=total_hns)

    # All good, check out
    payment = payments.generate_payment(name, email, mobile,address,country, cart, render.total_hns(cart, promo,True), promo)

    if payment == False:
        return render_template('payment.html', error='There was an error processing your payment', email=email, address=address, name=name,
            cart=cartHtml, total_usd=total_usd, total_hns=total_hns)

    finalPrice = payment['ID']
    HNSaddress = payment['HNSaddress']
    qr = f"<img src='/qr/{HNSaddress}' style='width: 200px; height: 200px;'>"

    # Center the QR code
    qr = f"<div style='text-align: center;'>{qr}</div>"

    responce = make_response(render_template('payment_info.html',cart=cartHtml, total_hns=finalPrice,address=HNSaddress, year=datetime.datetime.now().year, qr=qr))
    responce.set_cookie('cart', '[]')
    return responce

@app.route('/qr/<path:path>')
def qr(path):
    # Generate QR code
    qr = qrcode.make(path)
    
    # Save the QR code to a bytes buffer
    buffer = BytesIO()
    qr.save(buffer, format='PNG')
    buffer.seek(0)
    
    # Serve the image
    return send_file(buffer, mimetype='image/png')
    


# Promo routes
@app.route('/promo')
def promo():
    year = datetime.datetime.now().year
    # Check user is logged in
    token = request.cookies.get('token')
    if not token:
        return redirect('/login')
    
    if not account.token(token):
        return redirect('/login')

    promos = payments.getPromos()
    promos = render.promoList(promos)

    return render_template('promo.html', year=year, promos=promos)

@app.route('/promo', methods=['POST'])
def promo_post():
    data = request.form
    token = request.cookies.get('token')
    if not token:
        return redirect('/login')
    
    if not account.token(token):
        return redirect('/login')

    id = data['code']
    constant = data['constant']
    percent = data['percent']
    uses = data['uses']
    payments.addPromo(id, constant, percent, uses)

    return redirect('/promo')

@app.route('/promo/delete/<path:path>')
def promo_delete(path):
    token = request.cookies.get('token')
    if not token:
        return redirect('/login')
    
    if not account.token(token):
        return redirect('/login')

    payments.deletePromo(path)
    return redirect('/promo')

@app.route('/login', methods=['POST'])
def login():
    data = request.form
    token = account.login(data['email'], data['password'])
    if token:
        response = make_response(redirect('/promo'))
        response.set_cookie('token', token)
        return response
    return redirect('/login')


# Main routes
@app.route('/')
def index():
    year = datetime.datetime.now().year
    hns_scripts = '<script src="https://gday.hnsau/handshake.js" domain="gday.hnsau" async></script><script src="https://gday.hnsau/https.js" async></script>'

    if 'localhost' in request.host or '127.0.0.1' in request.host or DEV:
        hns_scripts = ''

    tld = request.host.split('.')[-1]
    if tld not in tlds and 'localhost' not in tld:
        return render_template('index.html',year=year, handshake_scripts=hns_scripts)
    
    hns_scripts = '<script src="https://gday.hnsau/https.js" async></script>'
    if 'localhost' in tld:
        tld = tlds[0]
        hns_scripts = ''
    
    return render_template('/tlds/'+tld+'.html',year=year, handshake_scripts=hns_scripts)

@app.route('/<path:path>')
def catch_all(path):
    year = datetime.datetime.now().year
    hns_scripts = '<script src="https://gday.hnsau/handshake.js" domain="gday.hnsau" async></script><script src="https://gday.hnsau/https.js" async></script>'

    if 'localhost' in request.host or '127.0.0.1' in request.host or DEV:
        hns_scripts = ''

    # If file exists, load it
    if os.path.isfile('templates/' + path):
        return render_template(path, year=year, handshake_scripts=hns_scripts)
    
    # Try with .html
    if os.path.isfile('templates/' + path + '.html'):
        return render_template(path + '.html', year=year, handshake_scripts=hns_scripts)
    
    if os.path.isfile('templates/' + path.strip('/') + '.html'):
        return render_template(path.strip('/') + '.html', year=year, handshake_scripts=hns_scripts)

    return render_template('404.html'), 404

# 404 catch all
@app.errorhandler(404)
def not_found(e):
    return render_template('404.html'), 404


def repeat_check_payments(auto=False):
    # Run check_payments function
    payments.check_payments()
    # Schedule the function to run again after 10 seconds
    if not auto:
        threading.Timer(10, repeat_check_payments).start()

def check_payments():
    print('Checking payments', flush=True)
    payments.check_payments()

if __name__ == '__main__':
    app.run(debug=True, port=5000, host='0.0.0.0')