#!/usr/bin/python3

# -------------------------------------------------------------------------------------------
#   "CP Admin" website User Sign-Up process, Incorporates HTML form 'cpadmin_signup.html'
#   Tests existence of email address. If new, emcrypts password, creates token,
#   and inserts row in Users table. Sends a verification email with token to unlock the User.

import os
import sys
sys.stdout.reconfigure(encoding='utf-8')
import json
import secrets, smtplib
import time
from email.mime.text import MIMEText
from dash_utils import get_connection, get_parameters, get_smtp_settings
import password_utils

# -------------------------------------------------------------------------------------------
from jinja2 import Environment, FileSystemLoader, Template
env = Environment(loader=FileSystemLoader('templates'), trim_blocks=True)

# -------------------------------------------------------------------------------------------
# functions
# -------------------------------------------------------------------------------------------

# -------------------------------------------------------------------------------------------
def render_form( tmpdict ):
    template = env.get_template('./cpadmin_signup.html')
    output = template.render( tmpdict )
    print(output)
# -------------------------------------------------------------------------------------------

# -------------------------------------------------------------------------------------------
def send_verification_email(recipient_email, verification_link):
    my_smtp = get_smtp_settings()
    SMTP_SERVER   = my_smtp.get('SMTP_SERVER','')
    SMTP_PORT     = my_smtp.get('SMTP_PORT','')
    SMTP_USER     = my_smtp.get('SMTP_USER','')
    SMTP_PASSWORD = my_smtp.get('SMTP_PASSWORD','')

    # -------------------------------------------------------------------------------------------
    subject = "CP Admin - Please verify your account"
    body = f"Click the following link to activate your account:\n{verification_link}"
    msg = MIMEText(body)
    msg["Subject"] = subject
    msg["From"] = SMTP_USER
    msg["To"] = recipient_email

    MAX_RETRIES = 3
    for attempt in range(1, MAX_RETRIES + 1):
        try:
            with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
                server.set_debuglevel(1)
                server.ehlo()
                server.starttls()
                server.ehlo()
                server.login(SMTP_USER, SMTP_PASSWORD)
                server.sendmail(SMTP_USER, [recipient_email], msg.as_string())
            return(True)  # print("E-Mail sent successfully")
            break
        except smtplib.SMTPResponseException as e:
            #  print(f"Attempt {attempt} failed: {e.smtp_code} {e.smtp_error}")
            if attempt == MAX_RETRIES or e.smtp_code != 454:
                return(False)
                raise
            #  print("Waiting before retrying...")
            time.sleep(10)  # wait 10 seconds before retrying
    return

# -------------------------------------------------------------------------------------------

def main():

    method = os.environ.get("REQUEST_METHOD", "GET")
    if method == "POST":
        # Form submission

        # extract form values
        args_dict = get_parameters()
        first_name = args_dict.get('first_name', '').strip()
        last_name = args_dict.get('last_name', '').strip()
        email = args_dict.get('email', '').strip()
        password = args_dict.get('password', '')

        if not first_name or not last_name or not email or not password:
            args_dict['message'] = "All fields are required"
            args_dict['severity'] = 'danger'
            render_form( args_dict )
            return

        db = get_connection()
        cur = db.cursor()

        # check for duplicates
        cur.execute("SELECT id FROM users WHERE email=%s", (email,))
        if cur.fetchone():
            to_login = f'<a class="alert-link" href="cpadmin_login.py?email={ email }">here</a>'
            to_reset = f'<a class="alert-link" href="cpadmin_reset_request.py?email={ email }">here</a>'
            args_dict['message'] = f'''
                E-Mail already registered!<br>
                Try logging in { to_login }.<br>
                To reset your password click { to_reset }.'''
            args_dict['severity'] = 'warning'
            render_form( args_dict )
            return

        token = secrets.token_hex(16)
        # hash password
        salt_b64, hash_b64 = password_utils.hash_password(password)

        # insert into DB
        try:
            cur.execute("""
                INSERT INTO users (
                    email, first_name, last_name, password_salt, password_hash,
                    verification_token, is_active)
                VALUES (%s, %s, %s, %s, %s, %s, 0)""",
                    (email, first_name, last_name, salt_b64, hash_b64, token)
                )
            db.commit()
            # if we're thru with the INSERT, send email with token
            recipient_email = email
            verification_link = f"https://admin.crosspurposeband.com/cgi-bin/cpadmin_active_token.py?token={ token }"
            email_sent = send_verification_email(recipient_email, verification_link)
            if email_sent :
                to_login = f'<a class="alert-link" href="/cgi-bin/cpadmin_login.py?email={ email }">here</a>'
                args_dict['message'] = f'''
                    Sign Up successful!<br>
                    Check E-Mail to validate the account.<br>
                    Then proceed to login, { to_login }.'''
                args_dict['severity'] = 'success'
            else:
                args_dict['message'] = "E-Mail failed to send."
                args_dict['severity'] = 'danger'
            render_form( args_dict )
        except Exception as e:
            args_dict['message'] = f"Error creating Users account: {e}"
            args_dict['severity'] = 'warning'
            render_form( args_dict )
            return
        finally:
            db.close()

    else:  # GET request
        # Just render the form, no message
        args_dict = get_parameters()
        render_form( args_dict )

# --- entry point ---
if __name__ == "__main__":
    main()
