import { UIElement } from '../../core/element.js';

/**
 * <chat-input-ui> — Composable chat input bar.
 *
 * Structure (stamped by default):
 *   <chat-input-ui>
 *     <textarea-ui placeholder="Type a message..." rows="1"></textarea-ui>
 *     <div slot="toolbar">
 *       <select-ui slot="model" placeholder="Model">...</select-ui>
 *       <button-ui icon="paper-plane-right" variant="primary" slot="send"></button-ui>
 *     </div>
 *   </chat-input-ui>
 *
 * Layout:
 *   ┌──────────────────────────────────┐
 *   │  textarea (grows vertically)     │
 *   ├──────────────────────────────────┤
 *   │  [model ▾]           [⏎ send]   │  ← toolbar
 *   └──────────────────────────────────┘
 *
 * Properties:
 *   models       — JSON array of model options: [{value, label}] or [{label, options: [...]}]
 *   model        — currently selected model value (reflected, two-way with select)
 *   placeholder  — textarea placeholder
 *   disabled     — disable entire input (textarea becomes contenteditable=false)
 *   loading      — in-flight / streaming state: send button disabled, submit
 *                  events suppressed, but textarea stays editable so the user
 *                  can draft a follow-up while the model is still responding.
 *
 * Events:
 *   submit   — user pressed Enter (without Shift) in the textarea or
 *              clicked the built-in send button (detail: { text, model,
 *              attachments }). Unconditional — Enter→submit is delegated
 *              from the inner <textarea-ui> which always emits a
 *              `submit` event on Enter without Shift. There is no
 *              [submit-on-enter] opt-in/opt-out attribute.
 *
 * Note:
 *   Composite wrapper, not a form field itself. The inner textarea-ui is
 *   form-associated via UIFormElement and submits through the parent
 *   form. `chat-input-ui`'s `disabled` / `placeholder` props propagate to
 *   the inner textarea.
 */
class UIChatInput extends UIElement {
  static properties = {
    disabled:    { type: Boolean, default: false, reflect: true },
    loading:     { type: Boolean, default: false, reflect: true },
    placeholder: { type: String,  default: 'Type a message...', reflect: true },
    model:       { type: String,  default: '', reflect: true },
  };

  static template = () => null;

  #textareaEl = null;
  #sendEl = null;
  #modelEl = null;
  #attachBtn = null;
  #models = [];

  #attachments = []; // [{ type: 'image', dataUrl, name }]
  #previewEl = null;
  #fileInput = null;
  #focusRaf = null;

  #onAttachPress = () => this.#fileInput?.click();
  #onFileInputChange = () => {
    if (this.#fileInput?.files?.length) this.#addImages(this.#fileInput.files);
    if (this.#fileInput) this.#fileInput.value = '';
  };

  get value() { return this.#textareaEl?.value?.trim() ?? ''; }
  get attachments() { return [...this.#attachments]; }

  /** Set model options programmatically: [{value, label}] or [{label, options: [...]}] */
  set models(list) {
    this.#models = list || [];
    if (this.#modelEl) {
      this.#modelEl.options = this.#models;
      // Set value after options so the display text resolves
      if (this.model) {
        this.#modelEl.value = this.model;
      }
    }
  }

  get models() { return this.#models; }

  connected() {
    if (!this.querySelector('[slot="toolbar"]')) {
      this.innerHTML = `
        <textarea-ui placeholder="${this.placeholder}" rows="1"></textarea-ui>
        <div slot="toolbar">
          <select-ui slot="model" placeholder="Model" aria-label="Select model" divider></select-ui>
          <button-ui icon="paper-plane-right" variant="ghost" slot="send" aria-label="Send message"></button-ui>
        </div>
      `;
    }

    this.#textareaEl = this.querySelector('textarea-ui');
    this.#sendEl = this.querySelector('[slot="send"]');
    this.#modelEl = this.querySelector('[slot="model"]');

    // Default aria-labels on author-provided send/model when not set —
    // these elements are screen-reader-relevant and shouldn't fall back
    // to the icon-name announcement.
    if (this.#sendEl && !this.#sendEl.hasAttribute('aria-label')) {
      this.#sendEl.setAttribute('aria-label', 'Send message');
    }
    if (this.#modelEl && !this.#modelEl.hasAttribute('aria-label')) {
      this.#modelEl.setAttribute('aria-label', 'Select model');
    }

    // Apply models if set before connected (options first, then value)
    if (this.#models.length && this.#modelEl) {
      this.#modelEl.options = this.#models;
      if (this.model) this.#modelEl.value = this.model;
    }

    // Image attach button + hidden file input
    const toolbar = this.querySelector('[slot="toolbar"]');
    if (toolbar && !toolbar.querySelector('[slot="attach"]')) {
      this.#fileInput = document.createElement('input');
      this.#fileInput.type = 'file';
      this.#fileInput.accept = 'image/*';
      this.#fileInput.multiple = true;
      this.#fileInput.style.display = 'none';
      this.appendChild(this.#fileInput);

      this.#attachBtn = document.createElement('button-ui');
      this.#attachBtn.setAttribute('icon', 'image');
      this.#attachBtn.setAttribute('variant', 'ghost');
      this.#attachBtn.setAttribute('slot', 'attach');
      this.#attachBtn.setAttribute('size', 'sm');
      this.#attachBtn.setAttribute('aria-label', 'Attach image');
      const sendBtn = toolbar.querySelector('[slot="send"]');
      toolbar.insertBefore(this.#attachBtn, sendBtn);
      this.#attachBtn.addEventListener('press', this.#onAttachPress);
      this.#fileInput.addEventListener('change', this.#onFileInputChange);
    }

    // Preview strip for attached images
    this.#previewEl = document.createElement('div');
    this.#previewEl.setAttribute('slot', 'preview');
    this.#previewEl.hidden = true;
    this.insertBefore(this.#previewEl, this.querySelector('[slot="toolbar"]'));

    // Paste handler for images
    this.addEventListener('paste', this.#onPaste);

    this.#sendEl?.addEventListener('press', this.#onSubmit);
    this.#textareaEl?.addEventListener('submit', this.#onSubmit);
    this.#modelEl?.addEventListener('change', this.#onModelChange);
    this.addEventListener('pointerdown', this.#onPointerDown);
  }

  render() {
    if (this.#textareaEl) {
      this.#textareaEl.disabled = this.disabled;
      this.#textareaEl.placeholder = this.placeholder;
    }
    if (this.#sendEl) {
      this.#sendEl.disabled = this.disabled || this.loading;
    }
    // Sync model value to select (handles late upgrades)
    if (this.#modelEl && this.model && this.#modelEl.value !== this.model) {
      this.#modelEl.value = this.model;
    }
  }

  #onPointerDown = (e) => {
    if (e.target.closest('button-ui, select-ui, input-ui, a')) return;
    this.#focusRaf = requestAnimationFrame(() => {
      this.#focusRaf = null;
      this.#textareaEl?.focus();
    });
  };

  #onModelChange = () => {
    this.model = this.#modelEl?.value || '';
  };

  #onSubmit = () => {
    if (this.disabled || this.loading) return;
    const text = this.value;
    if (!text && !this.#attachments.length) return;
    this.dispatchEvent(new CustomEvent('submit', {
      bubbles: true,
      detail: { text, model: this.model, attachments: this.attachments },
    }));
  };

  // ── Image handling ──

  #onPaste = (e) => {
    const items = e.clipboardData?.items;
    if (!items) return;
    const images = [...items].filter(i => i.type.startsWith('image/'));
    if (images.length === 0) return;
    e.preventDefault();
    const files = images.map(i => i.getAsFile()).filter(Boolean);
    if (files.length) this.#addImages(files);
  };

  #addImages(files) {
    for (const file of files) {
      const reader = new FileReader();
      reader.onload = () => {
        this.#attachments.push({ type: 'image', dataUrl: reader.result, name: file.name });
        this.#renderPreviews();
      };
      reader.readAsDataURL(file);
    }
  }

  #removeAttachment(index) {
    this.#attachments.splice(index, 1);
    this.#renderPreviews();
  }

  #renderPreviews() {
    if (!this.#previewEl) return;
    this.#previewEl.innerHTML = '';
    this.#previewEl.hidden = this.#attachments.length === 0;
    this.#attachments.forEach((a, i) => {
      const wrap = document.createElement('div');
      wrap.setAttribute('data-preview-item', '');
      const img = document.createElement('img');
      img.src = a.dataUrl;
      img.alt = a.name || 'attachment';
      const btn = document.createElement('button');
      btn.textContent = '×';
      btn.setAttribute('data-preview-remove', '');
      btn.addEventListener('click', () => this.#removeAttachment(i));
      wrap.appendChild(img);
      wrap.appendChild(btn);
      this.#previewEl.appendChild(wrap);
    });
  }

  clear() {
    this.#textareaEl?.clear();
    this.#attachments = [];
    if (this.#previewEl) { this.#previewEl.innerHTML = ''; this.#previewEl.hidden = true; }
  }

  focus() {
    this.#textareaEl?.focus();
  }

  disconnected() {
    if (this.#focusRaf != null) {
      cancelAnimationFrame(this.#focusRaf);
      this.#focusRaf = null;
    }
    this.removeEventListener('paste', this.#onPaste);
    this.#sendEl?.removeEventListener('press', this.#onSubmit);
    this.#textareaEl?.removeEventListener('submit', this.#onSubmit);
    this.#modelEl?.removeEventListener('change', this.#onModelChange);
    this.#attachBtn?.removeEventListener('press', this.#onAttachPress);
    this.#fileInput?.removeEventListener('change', this.#onFileInputChange);
    this.removeEventListener('pointerdown', this.#onPointerDown);
    this.#textareaEl = null;
    this.#sendEl = null;
    this.#modelEl = null;
    this.#attachBtn = null;
    this.#previewEl = null;
    this.#fileInput = null;
  }
}
customElements.define('chat-input-ui', UIChatInput);

export { UIChatInput };
