package app.service;

import app.config.SiteSecDBData;
import app.model.Users;

import ca.tecreations.StringTool;
import ca.tecreations.db.mysql.MySQL;
import ca.tecreations.misc.TimsTime;
import ca.tecreations.misc.TString;
import ca.tecreations.net.SSLEmail;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

/**
 *
 * @author Tim
 */
@Service
public class UsersEmailsService {
    @Autowired
    public SiteSecDBData data;

    public boolean debug = data.debug;
    
    public UsersEmailsService(SiteSecDBData data) {
        this.data = data;
    }
    
    public List<String> getAll(Users user) {
        List<String> emails = new ArrayList<>();
        String username = user.getUsername();
        if (username.contains("@")) {
            int index = username.indexOf("@");
            int second = username.indexOf("@", index + 1);
            if (second == -1) {
                emails.add(username); // assume an email, we won't allow @ otherwise
            }
        }
        List<List<String>> rows = data.getRows("SELECT email FROM emails WHERE uid='" + user.getUID() + "'", false);
        for (int i = 0; i < rows.size(); i++) {
            emails.add(rows.get(i).get(0));
        }
        return emails;
    }

    public void addActivation(String uid, String code) {
        data.issue("INSERT INTO account_ops (uid,op,txt,expiry) " + 
                "VALUES('" + uid + "','ACCOUNT_ACTIVATION','" + code + "','" +
                new TimsTime().getAltered("d+1") + "')",debug);
    }

    public void addEmail(Users user, String email) {
        // check less than or equal to max length
        if (email.length() > 320) {
            throw new IllegalArgumentException("UsersEmailsService.addEmail: length must be <= 320: (" + email.length() + ") : " + email);
        }
        // just do a cursory check for a multiple @ or not having a dot after the @
        int index = email.indexOf("@");
        if (index != -1) { // has at least one
            if (email.indexOf("@", index + 1) == -1) { // doesn't contain multiple @'s
                if (email.indexOf(".",email.indexOf("@") + 2) > 0) { // has at least one dot after the @ + 1 (one char domain label)
                    if (!hasExistingEmail(email)) {
                        data.issue("INSERT INTO emails (uid,email) VALUES('" + user.getUID() + "','" + email + "'",debug);
                    }
                }
            }
        }
    }

    public void addResetPassword(String uid, String code) {
        data.issue("INSERT INTO account_ops (uid,op,txt,expiry) " + 
                "VALUES('" + uid + "','RESET_PASSWORD','" + code + "','" +
                new TimsTime().getAltered("h+1") + "')",debug);
    }


    
    public void deleteByCode(String code) {
        data.issue("DELETE FROM account_ops WHERE txt='" + code + "'",debug);
    }

    public void deleteByUID(String uid) {
        data.issue("DELETE FROM account_ops WHERE uid='" + uid + "'",true);
    }

    public boolean hasExistingActivation(String uid) {
        List<List<String>> rows = data.getRows("SELECT * FROM account_ops WHERE uid='" + uid + "' AND op='ACTIVATE_ACCOUNT'", false);
        System.err.println("Rows: " + rows);
        if (rows.size() > 0) {
            if (!rows.get(0).get(3).equals("")) {
                return true;
            }
        }
        return false;
    }

    public boolean hasExistingEmail(String email) {
        List<List<String>> rows = data.getRows("SELECT * FROM emails WHERE email='" + email + "'",true);
        System.err.println("Rows: " + rows);
        if (rows.size() > 0) {
            if (rows.size() == 1) {
                return true;
            } else if (rows.size() > 1) {
                throw new IllegalArgumentException("hasExistingEmail: rows.size: " + rows.size() + " : " + rows);
            }
        }
        return false;
    }
    
    public boolean hasExistingPasswordReset(String uid) {
        List<List<String>> rows = data.getRows("SELECT * FROM account_ops WHERE uid='" + uid + "' AND op='RESET_PASSWORD'", false);
        System.err.println("Rows: " + rows);
        if (rows.size() > 0) {
            if (!rows.get(0).get(3).equals("")) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        String dbName = "sitesec_dev";
        String user = "sitesec_user";
        String pass = "eMZx06__xi9]O2q";
        MySQL mysql = new MySQL("tecreations.ca", 3306, dbName, user, pass.toCharArray());
        UsersEmailsService ues = new UsersEmailsService(new SiteSecDBData());

        List<List<String>> rows = mysql.getRows("SELECT * FROM users WHERE username='tim'", false);
        Long uid = -1L;
        String username = null;
        String password = null;
        String confirmation = null;
        boolean accountNonExpired = false;
        boolean accountNonLocked = false;
        boolean credentialsNonExpired = false;
        boolean enabled = false;
        String authoritiesList;
        List<GrantedAuthority> authorities = new ArrayList<>();
        if (rows.size() > 1) {
            System.err.println("Too many rows: " + rows);
        } else {
            List<String> row = rows.get(0);
            uid = Long.parseLong(row.get(0));
            username = row.get(1);
            password = row.get(2);
            accountNonExpired = Boolean.parseBoolean(row.get(3));
            accountNonLocked = Boolean.parseBoolean(row.get(4));
            credentialsNonExpired = Boolean.parseBoolean(row.get(5));
            enabled = Boolean.parseBoolean(row.get(6));
            authoritiesList = row.get(7);
            List<String> CSVs = StringTool.explode(authoritiesList, ',');
            for (int i = 0; i < CSVs.size(); i++) {
                String authority = mysql.getValue("SELECT authority FROM authorities WHERE id='" + CSVs.get(i) + "'");
                authorities.add(new SimpleGrantedAuthority(authority));
            }
        }

        Users data = new Users(uid, username, password, confirmation,
                accountNonExpired, accountNonLocked, credentialsNonExpired, enabled,
                authorities);
        ues.sendActivationEmail(data);
    }

    public void sendActivationEmail(Users user) {
        TString code = new TString(TString.BIG_ALPHA_NUM, 32);
        if (!hasExistingActivation("" + user.getUID())) {
            addActivation("" + user.getUID(), code.toString());
        }
        sendActivationEmail(user.getEmail(),code.toString());
        List<List<String>> rows = data.getRows("SELECT * FROM emails WHERE uid='" + user.getUID() + "'", false);
        if (rows.size() > 0) {
            if (debug) {
                System.out.println("\n\n");
                for(int i = 0;i < rows.size();i++) {
                    System.out.print(rows.get(i).get(2));
                }
                System.out.println("\n\n");
            }
            // add code to db with uid
            for (int i = 0; i < rows.size(); i++) {
                // send code and link in email
                sendActivationEmail(rows.get(i).get(2), code.toString());
            }
        }
    }

    private void sendActivationEmail(String email, String code) {
        String html = 
        "<h4>tecreations.ca</h4>\n" +
        "<a href='https://tecreations.ca:8443/activate?code=" + code + "'>Activate - " + email + "</a>\n";
        SSLEmail.send(email,"tecreations.ca User Registration Activation", html,null);
        SSLEmail.send("tim@tecreations.ca","User Registration - " + email, html,null);
    }

    public void sendResetPassword(Users user) {
        TString code = new TString(TString.BIG_ALPHA_NUM, 32);
        if (!hasExistingActivation("" + user.getUID())) {
            addResetPassword("" + user.getUID(), code.toString());
        }
        sendResetPasswordEmail(user.getEmail(),code.toString());
        List<List<String>> rows = data.getRows("SELECT * FROM emails WHERE uid='" + user.getUID() + "'", false);
        if (rows.size() > 0) {
            if (debug) {
                System.out.println("\n\n");
                for(int i = 0;i < rows.size();i++) {
                    System.out.print(rows.get(i).get(2));
                }
                System.out.println("\n\n");
            }
            // add code to db with uid
            for (int i = 0; i < rows.size(); i++) {
                // send code and link in email
                sendResetPasswordEmail(rows.get(i).get(2), code.toString());
            }
        }
    }

    private void sendResetPasswordEmail(String email, String code) {
        String html = 
        "<h4>tecreations.ca</h4>\n" +
        "<a href='https://tecreations.ca:8443/reset_pass?code=" + code + "'>Reset password - " + email + "</a>\n";
        SSLEmail.send(email,"tecreations.ca Password Reset Link", html,null);
        if (debug) SSLEmail.send("tim@tecreations.ca","Password Reset Request - " + email, html,null);
    }

    public void sendSignUpAttemptEmail(Users user) {
        System.out.println("sendSignUpAttemptEmail");
        data.setDebug(true);
        List<List<String>> userEmails = data.getRows("SELECT email FROM emails WHERE uid='" + user.getUID() + "'", false);
        List<List<String>> entry = data.getRows("SELECT txt,expiry FROM account_ops WHERE uid='" + user.getUID() + "'", false);
        if (entry.size() == 1) {
            String code = entry.get(0).get(0);
            String expiry = entry.get(0).get(1);

            if (!user.isEnabled() && new TimsTime().isLessThan(expiry)) {
                for(int i = 0; i < userEmails.size();i++) {
                    List<String> row = userEmails.get(i);
                    sendActivationEmail(row.get(0),code);
                }
            } else {
                String html = "";
                html += "An attempt to sign-up with your email occurred.<br />";
                html += "If this was not you, you can safely ignore this message.<br />";
                html += "You can <a href='/forgottenPassword'>Reset Your Password</a> ";
                html += "or <a href='/login'>login</a>.";
                for(int i = 0;i < userEmails.size();i++) {
                    SSLEmail.send(userEmails.get(i).get(0),"tecreations.ca User Registration Attempt",html,null);
                }
            }
        }
    }
}
