var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { assertExists, DisposableGroup } from '@blockeditor/global/utils';
import { ShadowlessElement, WithDisposable, } from '@blockeditor/lit';
import { nanoid } from '@blockeditor/store';
import { css, html, nothing } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { Bound } from '../../../../surface-block/utils/bound.js';
import { deserializeXYWH } from '../../../../surface-block/utils/xywh.js';
const DEFAULT_PREVIEW_CONTAINER_WIDTH = 280;
const DEFAULT_PREVIEW_CONTAINER_HEIGHT = 166;
const styles = css `
  .frame-preview-container {
    display: block;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    position: relative;
  }

  .frame-preview-surface-container {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    overflow: hidden;
  }

  .frame-preview-surface-viewport {
    max-width: 100%;
    box-sizing: border-box;
    margin: 0 auto;
    position: relative;
    overflow: hidden;
    pointer-events: none;
    user-select: none;
  }

  .frame-preview-surface-canvas-container {
    height: 100%;
    width: 100%;
    position: relative;
  }
`;
let FramePreview = class FramePreview extends WithDisposable(ShadowlessElement) {
    constructor() {
        super(...arguments);
        this.edgeless = null;
        this.surfaceWidth = DEFAULT_PREVIEW_CONTAINER_WIDTH;
        this.surfaceHeight = DEFAULT_PREVIEW_CONTAINER_HEIGHT;
        this.fillScreen = false;
        this._surfaceModel = null;
        this._surfaceRefRendererId = nanoid('unknown');
        this._edgelessDisposables = null;
        this._pageDisposables = null;
        this._frameDisposables = null;
        this._getViewportWH = (referencedModel) => {
            const [, , w, h] = deserializeXYWH(referencedModel.xywh);
            let scale = 1;
            if (this.fillScreen) {
                scale = Math.max(this.surfaceWidth / w, this.surfaceHeight / h);
            }
            else {
                scale = Math.min(this.surfaceWidth / w, this.surfaceHeight / h);
            }
            return {
                width: w * scale,
                height: h * scale,
            };
        };
        this._clearEdgelessDisposables = () => {
            this._edgelessDisposables?.dispose();
            this._edgelessDisposables = null;
        };
        this._clearPageDisposables = () => {
            this._pageDisposables?.dispose();
            this._pageDisposables = null;
        };
        this._clearFrameDisposables = () => {
            this._frameDisposables?.dispose();
            this._frameDisposables = null;
        };
    }
    get surfaceRenderer() {
        return this._surfaceRefRenderer.surfaceRenderer;
    }
    _attachRenderer() {
        if (this._surfaceRefRenderer?.surfaceRenderer.canvas.isConnected ||
            !this.container)
            return;
        this.surfaceRenderer.attach(this.container);
    }
    get _surfaceRefService() {
        const service = this.host.spec.getService('affine:surface-ref');
        assertExists(service, 'SurfaceRefBlockService not found');
        return service;
    }
    _setupSurfaceRefRenderer() {
        const surfaceRefService = this._surfaceRefService;
        const renderer = surfaceRefService.getRenderer(this._surfaceRefRendererId);
        this._surfaceRefRenderer = renderer;
        this._disposables.add(renderer.slots.surfaceModelChanged.on(model => {
            this._surfaceModel = model;
        }));
        this._disposables.add(renderer.slots.surfaceRendererRefresh.on(() => {
            this.requestUpdate();
        }));
        renderer.mount();
    }
    _cleanupSurfaceRefRenderer() {
        const surfaceRefService = this._surfaceRefService;
        surfaceRefService.removeRenderer(this._surfaceRefRendererId);
    }
    _refreshViewport() {
        if (!this.frame) {
            return;
        }
        const referencedModel = this.frame;
        // trigger a rerender to update element's size
        // and set viewport after element's size has been updated
        this.requestUpdate();
        this.updateComplete
            .then(() => {
            this.surfaceRenderer.onResize();
            this.surfaceRenderer.setViewportByBound(Bound.fromXYWH(deserializeXYWH(referencedModel.xywh)));
            this.blocksPortal?.setViewport(this.surfaceRenderer);
        })
            .catch(console.error);
    }
    _tryLoadFillScreen() {
        const surfaceService = this.host.spec.getService('affine:surface');
        this.fillScreen =
            surfaceService.editSession.getItem('presentFillScreen') ?? false;
    }
    _setEdgelessDisposables(edgeless) {
        this._clearEdgelessDisposables();
        if (!edgeless)
            return;
        this._edgelessDisposables = new DisposableGroup();
        this._edgelessDisposables.add(edgeless.slots.navigatorSettingUpdated.on(({ fillScreen }) => {
            if (fillScreen !== undefined) {
                this.fillScreen = fillScreen;
                this._refreshViewport();
            }
        }));
    }
    _setPageDisposables(page) {
        this._clearPageDisposables();
        this._pageDisposables = new DisposableGroup();
        this._pageDisposables.add(page.slots.blockUpdated.on(event => {
            const { type, flavour } = event;
            const isTopLevelBlock = ['affine:image', 'affine:note'].includes(flavour);
            if (!isTopLevelBlock)
                return;
            const frameBound = Bound.deserialize(this.frame.xywh);
            if (type === 'delete') {
                const deleteModel = event.model;
                const deleteBound = Bound.deserialize(deleteModel.xywh);
                if (frameBound.containsPoint([deleteBound.x, deleteBound.y])) {
                    this._refreshViewport();
                }
            }
            else {
                const topLevelBlock = page.getBlockById(event.id);
                if (!topLevelBlock)
                    return;
                const newBound = Bound.deserialize(topLevelBlock.xywh);
                if (frameBound.containsPoint([newBound.x, newBound.y])) {
                    this._refreshViewport();
                }
            }
        }));
    }
    _setFrameDisposables(frame) {
        this._clearFrameDisposables();
        this._frameDisposables = new DisposableGroup();
        this._frameDisposables.add(frame.propsUpdated.on(() => {
            this._refreshViewport();
        }));
    }
    _renderSurfaceContent(referencedModel) {
        const { width, height } = this._getViewportWH(referencedModel);
        return html `<div
      class="frame-preview-surface-container"
      style=${styleMap({
            width: `${this.surfaceWidth}px`,
            height: `${this.surfaceHeight}px`,
        })}
    >
      <div
        style=${styleMap({
            backgroundColor: referencedModel.background
                ? `var(${referencedModel.background})`
                : 'var(--affine-platte-transparent)',
            borderRadius: '4px',
        })}
      >
        <div
          class="frame-preview-surface-viewport"
          style=${styleMap({
            width: `${width}px`,
            height: `${height}px`,
            aspectRatio: `${width} / ${height}`,
        })}
        >
          <surface-ref-portal
            .page=${this.page}
            .host=${this.host}
            .containerModel=${referencedModel}
            .renderModel=${this.host.renderModel}
          ></surface-ref-portal>
          <div class="frame-preview-surface-canvas-container">
            <!-- attach canvas here -->
          </div>
        </div>
      </div>
    </div>`;
    }
    connectedCallback() {
        super.connectedCallback();
        this._tryLoadFillScreen();
        this._setupSurfaceRefRenderer();
        this._setPageDisposables(this.page);
        this._setEdgelessDisposables(this.edgeless);
        this._setFrameDisposables(this.frame);
    }
    updated(_changedProperties) {
        if (_changedProperties.has('frame')) {
            this._refreshViewport();
            this._setFrameDisposables(this.frame);
        }
        if (_changedProperties.has('edgeless')) {
            if (this.edgeless) {
                this._setEdgelessDisposables(this.edgeless);
            }
            else {
                this._clearEdgelessDisposables();
            }
        }
        if (_changedProperties.has('page')) {
            this._setPageDisposables(this.page);
        }
        this._attachRenderer();
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this._cleanupSurfaceRefRenderer();
        this._clearEdgelessDisposables();
        this._clearPageDisposables();
        this._clearFrameDisposables();
    }
    render() {
        const { _surfaceModel, frame, host } = this;
        const noContent = !_surfaceModel || !frame || !frame.xywh || !host;
        return html `<div class="frame-preview-container">
      ${noContent ? nothing : this._renderSurfaceContent(frame)}
    </div>`;
    }
};
FramePreview.styles = styles;
__decorate([
    property({ attribute: false })
], FramePreview.prototype, "edgeless", void 0);
__decorate([
    property({ attribute: false })
], FramePreview.prototype, "frame", void 0);
__decorate([
    property({ attribute: false })
], FramePreview.prototype, "page", void 0);
__decorate([
    property({ attribute: false })
], FramePreview.prototype, "host", void 0);
__decorate([
    property({ attribute: false })
], FramePreview.prototype, "surfaceWidth", void 0);
__decorate([
    property({ attribute: false })
], FramePreview.prototype, "surfaceHeight", void 0);
__decorate([
    state()
], FramePreview.prototype, "fillScreen", void 0);
__decorate([
    state()
], FramePreview.prototype, "_surfaceModel", void 0);
__decorate([
    query('.frame-preview-surface-canvas-container')
], FramePreview.prototype, "container", void 0);
__decorate([
    query('.frame-preview-surface-container surface-ref-portal')
], FramePreview.prototype, "blocksPortal", void 0);
FramePreview = __decorate([
    customElement('frame-preview')
], FramePreview);
export { FramePreview };
//# sourceMappingURL=frame-preview.js.map