import React, { useEffect, useRef } from "react";
import { createUniver, defaultTheme, LocaleType, merge } from "@univerjs/presets";
import { UniverDocsCorePreset } from "@univerjs/preset-docs-core";
import docsCoreEnUS from "@univerjs/preset-docs-core/locales/en-US";
import "@univerjs/preset-docs-core/lib/index.css";
// PICTURES AND LINKS (22/09/2026). Both were installed and neither was loaded, so the ribbon had no
// way to insert either — an organization designing its own agreement could not put its letterhead on
// it. Apache-2.0, the same licence as the core preset beside them; the Pro one is
// `preset-docs-advanced`, which this deliberately is not.
import { UniverDocsDrawingPreset } from "@univerjs/preset-docs-drawing";
import docsDrawingEnUS from "@univerjs/preset-docs-drawing/locales/en-US";
import "@univerjs/preset-docs-drawing/lib/index.css";
import { UniverDocsHyperLinkPreset } from "@univerjs/preset-docs-hyper-link";
import docsHyperLinkEnUS from "@univerjs/preset-docs-hyper-link/locales/en-US";
import "@univerjs/preset-docs-hyper-link/lib/index.css";

// The document itself — Univer's docs preset, the sibling of the sheets one the workbook editor
// runs on (FP-T26, C2b). Apache-2.0, and adopted rather than built.
//
// ONLY EVER REACHED BY A DYNAMIC IMPORT, for the reason SheetCanvas gives: this is a word processor,
// and every screen that is not this one would otherwise carry it.
//
// A BOOKMARK IS A CUSTOM RANGE, bound by the id the editor mints — never `{{mustache}}` text sitting
// in the prose. Text is what a typo, an autocorrect, or somebody retyping a sentence breaks, and it
// breaks silently, which is the only way a statutory document breaks badly. Everything the author
// does here to mark a blank goes through `insertBookmark` below, so there is one way to make one.
// Univer's layout px are the renderer's points / 0.75.
const PX_PER_PT = 1 / 0.75;

// A BODY WITH NO PAGE (25/09/2026). Only an EMPTY snapshot gets Univer's default page; one that
// carries a body but no `documentStyle.pageSize` — every seeded document, and anything saved from
// one — is laid out on an infinitely wide page: no line wraps and the left of the text is scrolled
// off the canvas. Give it the page the PDF renderer already falls back to (A4, and render-doc.js's
// margins), so the editor shows what prints. Anything the document does say is kept.
const withPage = (snapshot) => {
    if (!snapshot || !snapshot.body) return snapshot || {};
    const style = snapshot.documentStyle || {};
    if (style.pageSize?.width && style.pageSize?.height) return snapshot;

    return {
        ...snapshot,
        documentStyle: {
            documentFlavor: 1,
            marginTop: 57 * PX_PER_PT,
            marginBottom: 57 * PX_PER_PT,
            marginLeft: 51 * PX_PER_PT,
            marginRight: 51 * PX_PER_PT,
            ...style,
            pageSize: { width: 595.28 * PX_PER_PT, height: 841.89 * PX_PER_PT },
        },
    };
};

const DocCanvas = ({ snapshot, onReady }) => {
    const hostRef = useRef(null);
    const univerRef = useRef(null);

    useEffect(() => {
        if (!hostRef.current) return;

        const { univer, univerAPI } = createUniver({
            locale: LocaleType.EN_US,
            locales: { [LocaleType.EN_US]: merge({}, docsCoreEnUS, docsDrawingEnUS, docsHyperLinkEnUS) },
            theme: defaultTheme,
            presets: [
                UniverDocsCorePreset({ container: hostRef.current }),
                // An inserted picture is read into the snapshot as a data URL by Univer's own
                // default image service — there is no image store to run and nothing to serve. The
                // cost is that the document carries its pictures: a big photograph makes a big
                // template, and the renderer draws whatever arrives.
                UniverDocsDrawingPreset(),
                UniverDocsHyperLinkPreset(),
            ],
        });
        univerRef.current = univer;

        // An empty object is a valid document — Univer fills in one blank page — so a new template
        // and a saved one take the same path.
        const doc = univerAPI.createUniverDoc(withPage(snapshot));

        onReady?.({
            // getSnapshot, NOT save (25/09/2026): save() is the SPREADSHEET facade's, copied from
            // SheetCanvas. The document's has no such method, so every save threw here — in the
            // browser, before any request — and the author read "Could not save that form".
            snapshot: () => doc.getSnapshot(),

            // Mark whatever is selected as a blank the conversation fills in. Returns the id so the
            // caller can put it straight into the placeholder map — an author should never have to
            // copy one by hand.
            insertBookmark: (label) => {
                const id = `bm_${Math.random().toString(36).slice(2, 10)}`;
                const selection = doc.getSelection?.();
                const range = selection?.getActiveRange?.();
                if (!range) return null;

                // The id is OURS, not the editor's internal one, so the placeholder map and the
                // document agree on a name a person can read in both places.
                range.insertCustomRange?.(id, { label });

                return id;
            },

            // What is currently marked, so the map can show the bookmarks that really exist rather
            // than the ones somebody remembers adding.
            bookmarks: () => {
                const body = doc.getSnapshot()?.body || {};

                return (body.customRanges || []).map(r => ({ id: r.rangeId ?? r.id }));
            },
        });

        return () => {
            univerRef.current?.dispose();
            univerRef.current = null;
        };
        // Deliberately mount-only: re-creating the instance because a prop changed would throw away
        // whatever the author had written.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    return <div ref={hostRef} style={{ width: "100%", height: "100%", minHeight: 420 }}></div>;
};

export default DocCanvas;
