import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './demo.js';
import { richtextStyles } from './styles.js';
import { renderRichtext } from './template.js';
import type { IToolbarButton } from './types.js';
import '../../dees-icon/dees-icon.js';

import {
  customElement,
  type TemplateResult,
  property,
  html,
  state,
  query,
} from '@design.estate/dees-element';

import type { Editor } from '@tiptap/core';
import { DeesServiceLibLoader, type ITiptapBundle } from '../../../services/index.js';

declare global {
  interface HTMLElementTagNameMap {
    'dees-input-richtext': DeesInputRichtext;
  }
}



@customElement('dees-input-richtext')
export class DeesInputRichtext extends DeesInputBase<string> {
  public static demo = demoFunc;
  public static demoGroup = 'Input';

  // INSTANCE
  @property({
    type: String,
    reflect: true,
  })
  accessor value: string = '';

  @property({
    type: String,
  })
  accessor placeholder: string = '';

  @property({
    type: Boolean,
  })
  accessor showWordCount: boolean = true;

  @property({
    type: Number,
  })
  accessor minHeight: number = 200;

  @state()
  accessor showLinkInput: boolean = false;

  @state()
  accessor wordCount: number = 0;

  private editorElement: HTMLElement;
  private linkInputElement: HTMLInputElement;
  private tiptapBundle: ITiptapBundle | null = null;

  public editor: Editor;

  public static styles = richtextStyles;

  public render(): TemplateResult {
    return renderRichtext(this);
  }



  public renderToolbar(): TemplateResult {
    const buttons: IToolbarButton[] = this.getToolbarButtons();

    return html`
      ${buttons.map((button) => {
        if (button.isDivider) {
          return html`<div class="toolbar-divider"></div>`;
        }
        return html`
          <button
            class="toolbar-button ${button.isActive?.() ? 'active' : ''}"
            @click=${button.action}
            title=${button.title}
            ?disabled=${this.disabled || !this.editor}
          >
            <dees-icon .icon=${button.icon}></dees-icon>
          </button>
        `;
      })}
    `;
  }

  private getToolbarButtons(): IToolbarButton[] {
    if (!this.editor) return [];

    return [
      {
        name: 'bold',
        icon: 'lucide:bold',
        title: 'Bold (Ctrl+B)',
        action: () => this.editor.chain().focus().toggleBold().run(),
        isActive: () => this.editor.isActive('bold'),
      },
      {
        name: 'italic',
        icon: 'lucide:italic',
        title: 'Italic (Ctrl+I)',
        action: () => this.editor.chain().focus().toggleItalic().run(),
        isActive: () => this.editor.isActive('italic'),
      },
      {
        name: 'underline',
        icon: 'lucide:underline',
        title: 'Underline (Ctrl+U)',
        action: () => this.editor.chain().focus().toggleUnderline().run(),
        isActive: () => this.editor.isActive('underline'),
      },
      {
        name: 'strike',
        icon: 'lucide:strikethrough',
        title: 'Strikethrough',
        action: () => this.editor.chain().focus().toggleStrike().run(),
        isActive: () => this.editor.isActive('strike'),
      },
      { name: 'divider1', title: '', isDivider: true },
      {
        name: 'h1',
        icon: 'lucide:heading1',
        title: 'Heading 1',
        action: () => this.editor.chain().focus().toggleHeading({ level: 1 }).run(),
        isActive: () => this.editor.isActive('heading', { level: 1 }),
      },
      {
        name: 'h2',
        icon: 'lucide:heading2',
        title: 'Heading 2',
        action: () => this.editor.chain().focus().toggleHeading({ level: 2 }).run(),
        isActive: () => this.editor.isActive('heading', { level: 2 }),
      },
      {
        name: 'h3',
        icon: 'lucide:heading3',
        title: 'Heading 3',
        action: () => this.editor.chain().focus().toggleHeading({ level: 3 }).run(),
        isActive: () => this.editor.isActive('heading', { level: 3 }),
      },
      { name: 'divider2', title: '', isDivider: true },
      {
        name: 'bulletList',
        icon: 'lucide:list',
        title: 'Bullet List',
        action: () => this.editor.chain().focus().toggleBulletList().run(),
        isActive: () => this.editor.isActive('bulletList'),
      },
      {
        name: 'orderedList',
        icon: 'lucide:listOrdered',
        title: 'Numbered List',
        action: () => this.editor.chain().focus().toggleOrderedList().run(),
        isActive: () => this.editor.isActive('orderedList'),
      },
      {
        name: 'blockquote',
        icon: 'lucide:quote',
        title: 'Quote',
        action: () => this.editor.chain().focus().toggleBlockquote().run(),
        isActive: () => this.editor.isActive('blockquote'),
      },
      {
        name: 'code',
        icon: 'lucide:code',
        title: 'Code',
        action: () => this.editor.chain().focus().toggleCode().run(),
        isActive: () => this.editor.isActive('code'),
      },
      {
        name: 'codeBlock',
        icon: 'lucide:fileCode',
        title: 'Code Block',
        action: () => this.editor.chain().focus().toggleCodeBlock().run(),
        isActive: () => this.editor.isActive('codeBlock'),
      },
      { name: 'divider3', title: '', isDivider: true },
      {
        name: 'link',
        icon: 'lucide:link',
        title: 'Add Link',
        action: () => this.toggleLink(),
        isActive: () => this.editor.isActive('link'),
      },
      {
        name: 'alignLeft',
        icon: 'lucide:alignLeft',
        title: 'Align Left',
        action: () => this.editor.chain().focus().setTextAlign('left').run(),
        isActive: () => this.editor.isActive({ textAlign: 'left' }),
      },
      {
        name: 'alignCenter',
        icon: 'lucide:alignCenter',
        title: 'Align Center',
        action: () => this.editor.chain().focus().setTextAlign('center').run(),
        isActive: () => this.editor.isActive({ textAlign: 'center' }),
      },
      {
        name: 'alignRight',
        icon: 'lucide:alignRight',
        title: 'Align Right',
        action: () => this.editor.chain().focus().setTextAlign('right').run(),
        isActive: () => this.editor.isActive({ textAlign: 'right' }),
      },
      { name: 'divider4', title: '', isDivider: true },
      {
        name: 'undo',
        icon: 'lucide:undo',
        title: 'Undo (Ctrl+Z)',
        action: () => this.editor.chain().focus().undo().run(),
      },
      {
        name: 'redo',
        icon: 'lucide:redo',
        title: 'Redo (Ctrl+Y)',
        action: () => this.editor.chain().focus().redo().run(),
      },
    ];
  }

  public async firstUpdated() {
    await this.updateComplete;

    // Load Tiptap from CDN
    this.tiptapBundle = await DeesServiceLibLoader.getInstance().loadTiptap();

    this.editorElement = this.shadowRoot.querySelector('.editor-content');
    this.linkInputElement = this.shadowRoot.querySelector('.link-input input');
    this.initializeEditor();
  }

  private initializeEditor(): void {
    if (this.disabled || !this.tiptapBundle) return;

    const { Editor, StarterKit, Underline, TextAlign, Link, Typography } = this.tiptapBundle;

    this.editor = new Editor({
      element: this.editorElement,
      extensions: [
        StarterKit.configure({
          heading: {
            levels: [1, 2, 3],
          },
        }),
        Underline.configure({}),
        TextAlign.configure({
          types: ['heading', 'paragraph'],
        }),
        Link.configure({
          openOnClick: false,
          HTMLAttributes: {
            class: 'editor-link',
          },
        }),
        Typography.configure({}),
      ],
      content: this.value || (this.placeholder ? `<p>${this.placeholder}</p>` : ''),
      onUpdate: ({ editor }) => {
        this.value = editor.getHTML();
        this.updateWordCount();
        this.dispatchEvent(
          new CustomEvent('input', {
            detail: { value: this.value },
            bubbles: true,
            composed: true,
          })
        );
        this.dispatchEvent(
          new CustomEvent('change', {
            detail: { value: this.value },
            bubbles: true,
            composed: true,
          })
        );
      },
      onSelectionUpdate: () => {
        this.requestUpdate();
      },
      onFocus: () => {
        this.requestUpdate();
      },
      onBlur: () => {
        this.requestUpdate();
      },
    });

    this.updateWordCount();
  }

  private updateWordCount(): void {
    if (!this.editor) return;
    const text = this.editor.getText();
    this.wordCount = text.trim() ? text.trim().split(/\s+/).length : 0;
  }

  private toggleLink(): void {
    if (!this.editor) return;

    if (this.editor.isActive('link')) {
      const href = this.editor.getAttributes('link').href;
      this.showLinkInput = true;
      requestAnimationFrame(() => {
        if (this.linkInputElement) {
          this.linkInputElement.value = href || '';
          this.linkInputElement.focus();
          this.linkInputElement.select();
        }
      });
    } else {
      this.showLinkInput = true;
      requestAnimationFrame(() => {
        if (this.linkInputElement) {
          this.linkInputElement.value = '';
          this.linkInputElement.focus();
        }
      });
    }
  }

  public saveLink(): void {
    if (!this.editor || !this.linkInputElement) return;

    const url = this.linkInputElement.value;
    if (url) {
      this.editor.chain().focus().setLink({ href: url }).run();
    }
    this.hideLinkInput();
  }

  public removeLink(): void {
    if (!this.editor) return;
    this.editor.chain().focus().unsetLink().run();
    this.hideLinkInput();
  }

  public hideLinkInput(): void {
    this.showLinkInput = false;
    this.editor?.commands.focus();
  }

  public handleLinkInputKeydown(e: KeyboardEvent): void {
    if (e.key === 'Enter') {
      e.preventDefault();
      this.saveLink();
    } else if (e.key === 'Escape') {
      e.preventDefault();
      this.hideLinkInput();
    }
  }

  public setValue(value: string): void {
    this.value = value;
    if (this.editor && value !== this.editor.getHTML()) {
      this.editor.commands.setContent(value);
    }
  }

  public getValue(): string {
    return this.value;
  }

  public clear(): void {
    this.setValue('');
  }

  public focus(): void {
    this.editor?.commands.focus();
  }

  public async disconnectedCallback(): Promise<void> {
    await super.disconnectedCallback();
    if (this.editor) {
      this.editor.destroy();
    }
  }
}