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 {

    /**
     * Inserts a new user into the database.
     * @param uuId - The unique identifier for the user
     * @param firstName - The user's first name
     * @param lastName - The user's last name
     * @param username - The user's username
     * @param originUsername - The original username from the source platform
     * @param email - The user's email address
     * @param originEmail - The original email from the source platform
     * @param lang - The language for error messages ('fr' or 'en')
     * @returns The user's UUID if insertion was successful
     * @throws Error if the user cannot be registered
     */
    public static insertUser(
        uuId: string,
        firstName: string,
        lastName: string,
        username: string,
        originUsername: string,
        email: string,
        originEmail: string,
        lang: 'fr' | 'en' = 'fr'
    ): string {
        let insertResult: RunResult;
        try {
            const db: Database = System.getDb();
            const query: string = `
                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 params: SQLiteValue[] = [
                uuId,
                firstName,
                lastName,
                username,
                email,
                originEmail,
                originUsername,
                'desktop',
                0,
                1,
                Date.now()
            ];
            insertResult = db.run(query, params);
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.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 (insertResult.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.`);
        }
    }

    /**
     * Fetches user information from the database.
     * @param userId - The unique identifier of the user to fetch
     * @param lang - The language for error messages ('fr' or 'en')
     * @returns The user information object
     * @throws Error if the user is not found or cannot be retrieved
     */
    public static fetchUserInfos(userId: string, lang: 'fr' | 'en' = 'fr'): UserInfosQueryResponse {
        let userInfo: UserInfosQueryResponse | undefined;
        try {
            const db: Database = System.getDb();
            const query: string = `
                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 = ?
            `;
            const params: SQLiteValue[] = [userId];
            userInfo = db.get(query, params) as UserInfosQueryResponse | undefined;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.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 (!userInfo) {
            throw new Error(lang === 'fr' ? `Utilisateur non trouvé.` : `User not found.`);
        }
        return userInfo as UserInfosQueryResponse;
    }

    /**
     * Updates user information in the database.
     * @param userId - The unique identifier of the user to update
     * @param firstName - The new first name
     * @param lastName - The new last name
     * @param username - The new username
     * @param originUsername - The original username from the source platform
     * @param email - The new email address
     * @param originEmail - The original email from the source platform
     * @param originalAuthorName - The original author name
     * @param authorName - The new author name
     * @param lang - The language for error messages ('fr' or 'en')
     * @returns True if the update was successful, false otherwise
     * @throws Error if the update fails
     */
    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 query: string = `
                UPDATE erit_users
                SET first_name = ?, last_name = ?, username = ?, email = ?,
                    origin_username = ?, origin_author_name = ?, author_name = ?
                WHERE user_id = ? AND origin_email = ?
            `;
            const params: SQLiteValue[] = [
                firstName,
                lastName,
                username,
                email,
                originUsername,
                originalAuthorName,
                authorName,
                userId,
                originEmail
            ];
            const updateResult: RunResult = db.run(query, params);
            return updateResult.changes > 0;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.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.");
            }
        }
    }

    /**
     * Fetches account information for a user.
     * @param userId - The unique identifier of the user
     * @param lang - The language for error messages ('fr' or 'en')
     * @returns The user account information object
     * @throws Error if the account is not found or cannot be retrieved
     */
    public static fetchAccountInformation(userId: string, lang: 'fr' | 'en' = 'fr'): UserAccountQuery {
        let accountInfo: UserAccountQuery | undefined;
        try {
            const db: Database = System.getDb();
            const query: string = `
                SELECT first_name, last_name, username, author_name, email
                FROM erit_users
                WHERE user_id = ?
            `;
            const params: SQLiteValue[] = [userId];
            accountInfo = db.get(query, params) as UserAccountQuery | undefined;
        } catch (error: unknown) {
            if (error instanceof Error) {
                console.error(`DB Error: ${error.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 (!accountInfo) {
            throw new Error(lang === 'fr' ? `Compte non trouvé.` : `Account not found.`);
        }
        return accountInfo as UserAccountQuery;
    }
}
