import { getRestoreFolder } from '.';
import { ModelType } from '../../BaseModel';
import Folder from '../../models/Folder';
import Note from '../../models/Note';
import { FolderEntity, NoteEntity } from '../database/types';
import { checkObjectHasProperties } from '@joplin/utils/object';

export interface RestoreItemsOptions {
	targetFolderId?: string;

	// Restore item to a special "Restore" folder if the item doesn't have a non-deleted parent to
	// be restored to.
	useRestoreFolder?: boolean;
}

const restoreItems = async (itemType: ModelType, itemsOrIds: NoteEntity[] | FolderEntity[] | string[], options: RestoreItemsOptions = null) => {
	if (!itemsOrIds.length) return;

	options = {
		targetFolderId: null,
		useRestoreFolder: false,
		...options,
	};

	const ModelClass = itemType === ModelType.Note ? Note : Folder;

	let items: NoteEntity[] | FolderEntity[] = [];

	if (typeof itemsOrIds[0] === 'string') {
		items = await ModelClass.byIds(itemsOrIds as string[], { fields: ['id', 'parent_id', 'deleted_time'] });
	} else {
		items = itemsOrIds as (NoteEntity[] | FolderEntity[]);
	}

	let restoreFolder: FolderEntity = null;

	for (const item of items) {
		checkObjectHasProperties(item, ['id', 'parent_id']);

		let itemParentId = item.parent_id;

		const parentItem = await Folder.load(item.parent_id, { fields: ['id', 'deleted_time'] });
		if (!parentItem || parentItem.deleted_time) {
			if (options.useRestoreFolder) {
				if (!restoreFolder) restoreFolder = await getRestoreFolder();
				itemParentId = restoreFolder.id;
			} else {
				itemParentId = '';
			}
		}

		if (options.targetFolderId !== null) itemParentId = options.targetFolderId;

		let toSave: FolderEntity | NoteEntity = null;

		if (itemType === ModelType.Note) {
			// We need to preview conflicts -- they can be trashed.
			toSave = await Note.preview(item.id, { excludeConflicts: false });
		} else {
			toSave = await Folder.load(item.id);
		}

		toSave = {
			...toSave,
			deleted_time: 0,
			updated_time: Date.now(),
			parent_id: itemParentId,
		};

		await ModelClass.save(toSave, {
			autoTimestamp: false,
		});

		if (itemType === ModelType.Folder) {
			const childrenFolderIds = await Folder.childrenIds(item.id, { includeDeleted: true });
			const childrenFolders: FolderEntity[] = await Folder.byIds(childrenFolderIds, { fields: ['id', 'parent_id', 'deleted_time'] });
			const deletedChildrenFolders = childrenFolders.filter(f => !!f.deleted_time);
			await restoreItems(ModelType.Folder, deletedChildrenFolders);

			const notes = await Folder.notes(item.id, {
				fields: ['id', 'parent_id'],
				includeDeleted: true,
			});

			await restoreItems(ModelType.Note, notes);
		}
	}
};

export default restoreItems;