import { BlockModel, defineBlockSchema, nanoid } from '@blockeditor/store';
import { getTagColor } from '../_common/components/tags/colors.js';
import { multiSelectPureColumnConfig } from './common/columns/multi-select/define.js';
import { selectPureColumnConfig } from './common/columns/select/define.js';
import { titlePureColumnConfig } from './common/columns/title/define.js';
import { viewManager } from './common/data-view.js';
import { arrayMove, insertPositionToIndex } from './utils/insert.js';
export class DatabaseBlockModel extends BlockModel {
    getViewList() {
        return this.views;
    }
    initEmpty(viewType) {
        this.addColumn('start', titlePureColumnConfig.create(titlePureColumnConfig.name));
        this.addView(viewType);
    }
    initConvert(viewType) {
        this.addColumn('end', multiSelectPureColumnConfig.create('Tag', { options: [] }));
        this.initEmpty(viewType);
    }
    initTemplate(viewType) {
        const ids = [nanoid('unknown'), nanoid('unknown'), nanoid('unknown')];
        const statusId = this.addColumn('end', selectPureColumnConfig.create('Status', {
            options: [
                {
                    id: ids[0],
                    color: getTagColor(),
                    value: 'TODO',
                },
                {
                    id: ids[1],
                    color: getTagColor(),
                    value: 'In Progress',
                },
                {
                    id: ids[2],
                    color: getTagColor(),
                    value: 'Done',
                },
            ],
        }));
        for (let i = 0; i < 4; i++) {
            const rowId = this.page.addBlock('affine:paragraph', {
                text: new this.page.Text(`Task ${i + 1}`),
            }, this.id);
            this.updateCell(rowId, {
                columnId: statusId,
                value: ids[i],
            });
        }
        this.initEmpty(viewType);
    }
    addView(type) {
        const id = this.page.generateBlockId();
        const viewConfig = viewManager.getView(type);
        const view = viewConfig.init(this, id, viewConfig.defaultName);
        this.page.transact(() => {
            this.views.push(view);
        });
        return view;
    }
    duplicateView(id) {
        const newId = this.page.generateBlockId();
        this.page.transact(() => {
            const index = this.views.findIndex(v => v.id === id);
            const view = this.views[index];
            if (view) {
                this.views.splice(index + 1, 0, JSON.parse(JSON.stringify({ ...view, id: newId })));
            }
        });
        return newId;
    }
    deleteView(id) {
        this.page.captureSync();
        this.page.transact(() => {
            this.views = this.views.filter(v => v.id !== id);
        });
    }
    updateView(id, update) {
        this.page.transact(() => {
            this.views = this.views.map(v => {
                if (v.id !== id) {
                    return v;
                }
                return { ...v, ...update(v) };
            });
        });
        this.applyViewsUpdate();
    }
    moveViewTo(id, position) {
        this.page.transact(() => {
            this.views = arrayMove(this.views, v => v.id === id, arr => insertPositionToIndex(position, arr));
        });
        this.applyViewsUpdate();
    }
    applyViewsUpdate() {
        this.page.updateBlock(this, {
            views: this.views,
        });
    }
    applyColumnUpdate() {
        this.page.updateBlock(this, {
            columns: this.columns,
        });
    }
    findColumnIndex(id) {
        return this.columns.findIndex(v => v.id === id);
    }
    getColumn(id) {
        return this.columns.find(v => v.id === id);
    }
    addColumn(position, column) {
        const id = column.id ?? this.page.generateBlockId();
        if (this.columns.find(v => v.id === id)) {
            return id;
        }
        this.page.transact(() => {
            const col = {
                ...column,
                id,
            };
            this.columns.splice(insertPositionToIndex(position, this.columns), 0, col);
        });
        return id;
    }
    updateColumn(id, updater) {
        const index = this.columns.findIndex(v => v.id === id);
        if (index == null) {
            return;
        }
        this.page.transact(() => {
            const column = this.columns[index];
            this.columns[index] = { ...column, ...updater(column) };
        });
        return id;
    }
    deleteColumn(columnId) {
        const index = this.findColumnIndex(columnId);
        if (index < 0)
            return;
        this.page.transact(() => {
            this.columns.splice(index, 1);
        });
    }
    getCell(rowId, columnId) {
        if (columnId === 'title') {
            return {
                columnId: 'title',
                value: rowId,
            };
        }
        const yRow = this.cells[rowId];
        const yCell = yRow?.[columnId] ?? null;
        if (!yCell)
            return null;
        return {
            columnId: yCell.columnId,
            value: yCell.value,
        };
    }
    updateCell(rowId, cell) {
        const hasRow = rowId in this.cells;
        if (!hasRow) {
            this.cells[rowId] = Object.create(null);
        }
        this.page.transact(() => {
            this.cells[rowId][cell.columnId] = {
                columnId: cell.columnId,
                value: cell.value,
            };
        });
    }
    copyCellsByColumn(fromId, toId) {
        this.page.transact(() => {
            Object.keys(this.cells).forEach(rowId => {
                const cell = this.cells[rowId][fromId];
                if (cell) {
                    this.cells[rowId][toId] = {
                        ...cell,
                        columnId: toId,
                    };
                }
            });
        });
    }
    updateCells(columnId, cells) {
        this.page.transact(() => {
            Object.entries(cells).forEach(([rowId, value]) => {
                this.cells[rowId][columnId] = {
                    columnId,
                    value,
                };
            });
        });
    }
}
const migration = {
    toV3: data => {
        const id = nanoid('unknown');
        // @ts-expect-error
        const title = data['titleColumnName'];
        // @ts-expect-error
        const width = data['titleColumnWidth'];
        // @ts-expect-error
        delete data['titleColumnName'];
        // @ts-expect-error
        delete data['titleColumnWidth'];
        data.columns.unshift({
            id,
            type: 'title',
            name: title,
            data: {},
        });
        data.views.forEach(view => {
            if (view.mode === 'table') {
                view.columns.unshift({
                    id,
                    width,
                });
            }
        });
    },
};
export const DatabaseBlockSchema = defineBlockSchema({
    flavour: 'affine:database',
    props: (internal) => ({
        views: [],
        title: internal.Text(),
        cells: Object.create(null),
        columns: [],
    }),
    metadata: {
        role: 'hub',
        version: 3,
        parent: ['affine:note'],
        children: ['affine:paragraph', 'affine:list'],
    },
    toModel: () => new DatabaseBlockModel(),
    onUpgrade: (data, previousVersion, latestVersion) => {
        if (previousVersion < 3 && latestVersion >= 3) {
            migration.toV3(data);
        }
    },
});
//# sourceMappingURL=database-model.js.map