import { getUserEncryptionKey } from "../keyManager.js";
import System from "../System.js";
import IssueRepository, { IssueQuery } from "../repositories/issue.repository.js";
import RemovedItem from "./RemovedItem.js";

/**
 * Represents a synced issue with its metadata.
 */
export interface SyncedIssue {
    id: string;
    name: string;
    lastUpdate: number;
}

/**
 * Represents the basic properties of an issue.
 */
export interface IssueProps {
    id: string;
    name: string;
}

/**
 * Model class for managing issues associated with books.
 * Provides methods for CRUD operations on issues with encryption support.
 */
export default class Issue {
    /**
     * Retrieves all issues associated with a specific book.
     * Decrypts issue names using the user's encryption key.
     *
     * @param userId - The unique identifier of the user.
     * @param bookId - The unique identifier of the book.
     * @param lang - The language for error messages ('fr' or 'en'). Defaults to 'fr'.
     * @returns A promise resolving to an array of decrypted issues.
     */
    public static async getIssuesFromBook(
        userId: string,
        bookId: string,
        lang: 'fr' | 'en' = 'fr'
    ): Promise<IssueProps[]> {
        const issueQueryResults: IssueQuery[] = IssueRepository.fetchIssuesFromBook(userId, bookId, lang);
        const userEncryptionKey: string = getUserEncryptionKey(userId);
        const decryptedIssues: IssueProps[] = [];

        if (issueQueryResults.length > 0) {
            for (const issueRecord of issueQueryResults) {
                decryptedIssues.push({
                    id: issueRecord.issue_id,
                    name: System.decryptDataWithUserKey(issueRecord.name, userEncryptionKey)
                });
            }
        }

        return decryptedIssues;
    }

    /**
     * Creates a new issue for a book.
     * Encrypts and hashes the issue name before storage.
     *
     * @param userId - The unique identifier of the user.
     * @param bookId - The unique identifier of the book.
     * @param name - The plain text name of the issue.
     * @param lang - The language for error messages ('fr' or 'en'). Defaults to 'fr'.
     * @param existingIssueId - Optional existing issue ID for syncing purposes.
     * @returns The unique identifier of the created issue.
     */
    public static addNewIssue(
        userId: string,
        bookId: string,
        name: string,
        lang: 'fr' | 'en' = 'fr',
        existingIssueId?: string
    ): string {
        const userEncryptionKey: string = getUserEncryptionKey(userId);
        const encryptedName: string = System.encryptDataWithUserKey(name, userEncryptionKey);
        const hashedName: string = System.hashElement(name);
        const issueId: string = existingIssueId || System.createUniqueId();

        return IssueRepository.insertNewIssue(issueId, userId, bookId, encryptedName, hashedName, lang);
    }

    /**
     * Removes an issue from the database.
     *
     * @param userId - The unique identifier of the user.
     * @param bookId - The unique identifier of the book.
     * @param issueId - The unique identifier of the issue to remove.
     * @param deletedAt - The timestamp of deletion.
     * @param lang - The language for error messages ('fr' or 'en'). Defaults to 'fr'.
     * @returns True if the issue was successfully removed, false otherwise.
     */
    public static removeIssue(
        userId: string,
        bookId: string,
        issueId: string,
        deletedAt: number = System.timeStampInSeconds(),
        lang: 'fr' | 'en' = 'fr'
    ): boolean {
        const deleted: boolean = IssueRepository.deleteIssue(userId, issueId, lang);
        if (deleted) {
            RemovedItem.deleteTracker(userId, bookId, 'book_issues', issueId, deletedAt, lang);
        }
        return deleted;
    }
}
