import {
  DecoratorNode,
  DOMExportOutput,
  LexicalNode,
  NodeKey,
  SerializedLexicalNode,
  Spread,
} from 'lexical';
import React from 'react';
import { ContractBlockComponent } from './ContractBlockComponent';

export type SerializedContractBlockNode = Spread<
  {
    contractId: string;
    contractName: string;
  },
  SerializedLexicalNode
>;

export class ContractBlockNode extends DecoratorNode<JSX.Element> {
  __contractId: string;
  __contractName: string;

  static getType(): string {
    return 'contract-block';
  }

  static clone(node: ContractBlockNode): ContractBlockNode {
    return new ContractBlockNode(node.__contractId, node.__contractName, node.__key);
  }

  constructor(contractId: string, contractName: string, key?: NodeKey) {
    super(key);
    this.__contractId = contractId;
    this.__contractName = contractName;
  }

  createDOM(): HTMLElement {
    const div = document.createElement('div');
    div.className = 'contract-block-wrapper';
    return div;
  }

  updateDOM(): boolean {
    return false;
  }

  decorate(): JSX.Element {
    return (
      <ContractBlockComponent
        contractId={this.__contractId}
        contractName={this.__contractName}
      />
    );
  }

  exportJSON(): SerializedContractBlockNode {
    return {
      ...super.exportJSON(),
      type: 'contract-block',
      contractId: this.__contractId,
      contractName: this.__contractName,
      version: 1,
    };
  }

  static importJSON(serializedNode: SerializedContractBlockNode): ContractBlockNode {
    return $createContractBlockNode(
      serializedNode.contractId,
      serializedNode.contractName
    );
  }

  isInline(): boolean {
    return false;
  }

  canInsertTextBefore(): boolean {
    return false;
  }

  canInsertTextAfter(): boolean {
    return false;
  }

  exportDOM(): DOMExportOutput {
    const element = document.createElement('div');
    element.className = 'contract-block-wrapper';
    element.setAttribute('data-contract-id', this.__contractId);
    element.textContent = `[Contract: ${this.__contractName}]`;
    return { element };
  }
}

export function $createContractBlockNode(
  contractId: string,
  contractName: string
): ContractBlockNode {
  return new ContractBlockNode(contractId, contractName);
}

export function $isContractBlockNode(
  node: LexicalNode | null | undefined,
): node is ContractBlockNode {
  return node instanceof ContractBlockNode;
}
