import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
import System from "../System.js";

export interface UserInfosQueryResponse extends Record<string, SQLiteValue> {
    first_name: string;
    last_name: string;
    username: string;
    email: string;
    plateform: string;
    term_accepted: number;
    account_verified: number;
    author_name: string;
    writing_lang: number;
    writing_level: number;
    rite_points: number;
    user_group: number;
}

export interface CredentialResponse {
    valid: boolean;
    message?: string;
    user?: UserResponse;
}

interface UserResponse {
    id: string;
    name: string;
    last_name: string;
    username: string;
    email: string;
    account_verified: boolean;
}

export interface UserAccountQuery extends Record<string, SQLiteValue> {
    first_name: string;
    last_name: string;
    username: string;
    author_name: string;
    email: string;
}

export interface GuideTourResult extends Record<string, SQLiteValue> {
    step_tour: string;
}

export default class UserRepo {

    public static insertUser(uuId: string, firstName: string, lastName: string, username: string, originUsername: string, email: string, originEmail: string, lang: 'fr' | 'en' = 'fr'): string {
        let result: RunResult;
        try {
            const db: Database = System.getDb();
            const query = `INSERT INTO erit_users (user_id, first_name, last_name, username, email, origin_email,
                                                   origin_username, plateform, term_accepted,
                                                   account_verified, reg_date)
                           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
            const values: (string | null | number)[] = [
                uuId,
                firstName,
                lastName,
                username,
                email,
                originEmail,
                originUsername,
                'desktop', // plateform
                0, // term_accepted
                1, // account_verified
                Date.now() // reg_date (current timestamp)
            ];
            result = db.run(query, values);
        } catch (e: unknown) {
            if (e instanceof Error) {
                console.error(`DB Error: ${e.message}`);
                throw new Error(lang === 'fr' ? `Impossible d'enregistrer l'utilisateur.` : `Unable to register user.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
        if (result.changes > 0) {
            return uuId;
        } else {
            throw new Error(lang === 'fr' ? `Une erreur s'est produite lors de l'enregistrement de l'utilisateur.` : `Error registering user.`);
        }
    }

    public static fetchUserInfos(userId: string, lang: 'fr' | 'en' = 'fr'): UserInfosQueryResponse {
        let result;
        try {
            const db: Database = System.getDb();
            result = db.get('SELECT first_name, last_name, username, email, plateform, term_accepted, account_verified, author_name, erite_points AS rite_points, user_group FROM erit_users WHERE user_id=?', [userId]);
        } catch (e: unknown) {
            if (e instanceof Error) {
                console.error(`DB Error: ${e.message}`);
                throw new Error(lang === 'fr' ? `Impossible de récupérer les informations utilisateur.` : `Unable to retrieve user information.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
        if (!result) {
            throw new Error(lang === 'fr' ? `Utilisateur non trouvé.` : `User not found.`);
        }
        return result as UserInfosQueryResponse;
    }

    public static updateUserInfos(userId: string, firstName: string, lastName: string, username: string, originUsername: string, email: string, originEmail: string, originalAuthorName: string, authorName: string, lang: 'fr' | 'en' = 'fr'): boolean {
        try {
            const db: Database = System.getDb();
            const result: RunResult = db.run('UPDATE `erit_users` SET `first_name`=?, `last_name`=?, `username`=?, email=?,`origin_username`=?, origin_author_name=? ,author_name=? WHERE user_id=? AND `origin_email`=?', [firstName, lastName, username, email, originUsername, originalAuthorName, authorName, userId, originEmail]);
            return result.changes > 0;
        } catch (e: unknown) {
            if (e instanceof Error) {
                console.error(`DB Error: ${e.message}`);
                throw new Error(lang === 'fr' ? `Impossible de mettre à jour les informations utilisateur.` : `Unable to update user information.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
    }

    public static fetchAccountInformation(userId: string, lang: 'fr' | 'en' = 'fr'): UserAccountQuery {
        let result;
        try {
            const db: Database = System.getDb();
            result = db.get('SELECT first_name, last_name, username, author_name, email FROM erit_users WHERE user_id=?', [userId]);
        } catch (e: unknown) {
            if (e instanceof Error) {
                console.error(`DB Error: ${e.message}`);
                throw new Error(lang === 'fr' ? `Impossible de récupérer les informations du compte.` : `Unable to retrieve account information.`);
            } else {
                console.error("An unknown error occurred.");
                throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
            }
        }
        if (!result) {
            throw new Error(lang === 'fr' ? `Compte non trouvé.` : `Account not found.`);
        }
        return result as UserAccountQuery;
    }
}
