import React from 'react';
import { Root, createRoot } from 'react-dom/client';
import { updateSiteColors } from '../tmdet-extension/tmdet-color-theme';
import { RcsbFv, RcsbFvBoardConfigInterface } from '@rcsb/rcsb-saguaro';
import { fetchDescriptor } from '../UniTmpHelper';
import { setExternalRowTitleComponent, setRegionColors } from '../FeatureViewConfig';
import { TmRowTitleComponent } from './TmRowTitleComponent';

const defaultViewerWidth = 600;
const defaultRowTitleWidth = 100;
const ULTIMATE_GAP_CONSTANT = 4; // I do not know why it is 4.

type TmFv1DParams = {
    elementId: string,
    url: string,
    side1: string,
    trackWidth?: number,
    rowTitleWidth?: number,
    autoResize?: boolean
};

type TmFv1DState = {
    featureViewer?: RcsbFv,
    num?: number
};


export class TmFv1D extends React.Component<TmFv1DParams, TmFv1DState> {

    protected containerRef = React.createRef<HTMLDivElement>();

    public constructor(props: TmFv1DParams) {
        super(props);
    }

    public async componentDidMount(): Promise<void> {
        await createRcsbFeatureViewer({
            elementId: this.props.elementId,
            url: this.props.url,
            side1: this.props.side1,
            rowTitleWidth: this.props.rowTitleWidth,
            trackWidth: this.props.trackWidth
        });

        if (this.props.autoResize) {
            new ResizeObserver(this.resize)
                .observe(this.containerRef.current as Element);
        }
    }

    resize(entries: ResizeObserverEntry[], observer: ResizeObserver) {
        const currentId = entries[0].target.id;
        const observerEntry = entries[0];
        const featureViewer = featureViewerRegistry.get(currentId) as RcsbFv;
        const boardConfig = featureViewer.getBoardConfig();
        boardConfig.trackWidth = observerEntry.contentRect.width - boardConfig.rowTitleWidth!;
        resizeBoardConfigTrackWidth(boardConfig, observerEntry.contentRect.width);

        featureViewer.updateBoardConfig({ boardConfigData: boardConfig });
    }

    public render(): JSX.Element {
        return (
            <div ref={this.containerRef}
                id={ this.props.elementId }
                style={{ borderWidth: "0px", padding: "0px" }}
            />
        );
    }

}

export class TmFv1DElement extends HTMLElement {

    connectedCallback() {
        const root = createRoot(this);
        setTimeout(() => this.render(root), 1000);
    }

    render(root: Root) {

        let autoResize = true;
        if (this.hasAttribute("autoResize")) {
            const value = this.getAttribute("autoResize");
            autoResize = (value == "true");
        }

        const elementId = this.getAttribute("elementId")!;
        const url = this.getAttribute("url")!;
        const side1 = this.getAttribute("side1")!;
        const calculatedWidth = calculateViewerWidth(this.parentElement);
        const rowTitleWidth = parseInt(this.getAttribute("rowTitleWidth")!)
            || defaultRowTitleWidth;
        let trackWidth = !autoResize
            ? parseInt(this.getAttribute("trackWidth")!) || (defaultViewerWidth - ULTIMATE_GAP_CONSTANT)
            : calculatedWidth;
        trackWidth -= rowTitleWidth;
        console.log('Widths:', [ rowTitleWidth, trackWidth ]);

        root.render(
            <TmFv1D
                elementId={ elementId }
                url={ url }
                side1={ side1 }
                trackWidth={ trackWidth }
                rowTitleWidth={ rowTitleWidth }
                autoResize={ autoResize }
            />
        );
    }
}

function calculateViewerWidth(parent: HTMLElement|null) {
    if (!parent) {
        return defaultViewerWidth;
    }
    const boundingRect = parent.getBoundingClientRect();
    const computedStyle = window.getComputedStyle(parent);
    const extraWidth = parseInt(computedStyle.paddingLeft)
        + parseInt(computedStyle.paddingRight)
        + parseInt(computedStyle.borderLeftWidth)
        + parseInt(computedStyle.borderRightWidth);

    return boundingRect.width - extraWidth - ULTIMATE_GAP_CONSTANT;
}

const featureViewerRegistry = new Map();

/**
 * Create an Rcsb Saguaro 1D viewer instance.
 *
 * @param elementId id of parent element
 * @param url source of JSON config
 * @param side1 side1 paramter to update site colors, if it is needed
 */
export async function createRcsbFeatureViewer(params: {
    elementId: string, url: string, side1: string, trackWidth?: number, rowTitleWidth?: number }): Promise<RcsbFv> {

    updateSiteColors(params.side1 as any);

    const featureTracks = await fetchDescriptor(params.url);
    const blockConfig = featureTracks.blockConfig;
    const boardConfig = blockConfig[0].featureViewConfig[0].boardConfig;
    boardConfig.trackWidth = params.trackWidth ?? 600;
    boardConfig.rowTitleWidth = params.rowTitleWidth ?? 160;

    const rowConfig = blockConfig[0].featureViewConfig[0].rowConfig;
    setRegionColors(rowConfig);

    setExternalRowTitleComponent(rowConfig);

    const pfv = new RcsbFv({
        boardConfigData: boardConfig,
        rowConfigData: rowConfig,
        elementId: params.elementId
    });
    featureViewerRegistry.set(params.elementId, pfv);

    return pfv;
}

function resizeBoardConfigTrackWidth(boardConfig: RcsbFvBoardConfigInterface, width: number) {
    const fullWidth = width - ULTIMATE_GAP_CONSTANT;
    boardConfig.trackWidth = fullWidth - boardConfig.rowTitleWidth!;
}
