// csvtextarea.js
import { parseCSV, parseCSVRow, stringifyCSV } from './parseCSV.js';

class CSVTextarea extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.isComponentInitialized = false;
  }

  static get observedAttributes() {
    return ['column-headings', 'id', 'class', 'caption', 'text', 'placeholder', 'css-href', 'debug'];
  }

  attributeChangedCallback(name, old, newVal) {
    if (name === 'column-headings' && this.isComponentInitialized) {
      this.initializeTable();
    }
  }

  async connectedCallback() {
    await this.initializeComponent();
    this.isComponentInitialized = true;
    this.initializeTable();
    this.setupEventListeners();
  }

  async initializeComponent() {
    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid black; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        input { width: 100%; }
      </style>
      <table>
        <thead></thead>
        <tbody></tbody>
      </table>
      <button id="append-row">Append Row</button>
      <button id="cleanup">Cleanup</button>
      ${this.hasAttribute('debug') ? '<button id="debug">Debug</button>' : ''}
      ${this.hasAttribute('title') || this.hasAttribute('help-description') ? '<span id="help-icon">ⓘ</span>' : ''}
    `;

    this.shadowRoot.appendChild(template.content.cloneNode(true));

    if (this.hasAttribute('css-href')) {
      const link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = this.getAttribute('css-href');
      this.shadowRoot.appendChild(link);
    }

    if (this.hasAttribute('title') || this.hasAttribute('help-description')) {
      const helpIcon = this.shadowRoot.getElementById('help-icon');
      helpIcon.addEventListener('click', () => {
        alert(`${this.getAttribute('title') || ''}\n${this.getAttribute('help-description') || ''}`);
      });
    }
  }

  initializeTable() {
    const headings = parseCSVRow(this.getAttribute('column-headings'));
    const table = this.shadowRoot.querySelector('table');
    const thead = table.querySelector('thead');
    const tbody = table.querySelector('tbody');

    // Clear existing headings
    thead.innerHTML = '';

    // Create table headings
    const tr = document.createElement('tr');
    headings.forEach(heading => {
      const th = document.createElement('th');
      th.textContent = heading;
      tr.appendChild(th);
    });
    thead.appendChild(tr);

    // Populate table body
    const textarea = this.querySelector('textarea');
    if (textarea && textarea.value.trim()) {
      this.fromTextarea();
    } else {
      this.appendRow();
    }

    // Clone datalists into the shadow DOM
    const datalists = this.querySelectorAll('datalist');
    datalists.forEach(datalist => {
      this.shadowRoot.appendChild(datalist.cloneNode(true));
    });

    // Associate datalists with columns
    headings.forEach((heading, index) => {
      const datalist = this.shadowRoot.querySelector(`datalist#${heading.toLowerCase()}`);
      if (datalist) {
        this.setAutocomplete(index, Array.from(datalist.options).map(option => ({ value: option.value })));
      }
    });
  }

  setupEventListeners() {
    this.shadowRoot.querySelector('#append-row').addEventListener('click', () => this.appendRow());
    this.shadowRoot.querySelector('#cleanup').addEventListener('click', () => this.cleanupTable());

    if (this.hasAttribute('debug')) {
      this.shadowRoot.querySelector('#debug').addEventListener('click', () => {
        console.log(this.toCSV());
      });
    }

    this.shadowRoot.querySelector('tbody').addEventListener('input', event => {
      if (event.target.tagName === 'INPUT') {
        const rowIndex = event.target.closest('tr').rowIndex - 1;
        const colIndex = event.target.closest('td').cellIndex;
        const value = event.target.value;
        this.dispatchEvent(new CustomEvent('changed', { detail: { rowIndex, colIndex, value } }));
        if (this.hasAttribute('debug')) {
          console.log(`Cell changed: Row ${rowIndex}, Col ${colIndex}, Value ${value}`);
        }
      }
    });

    this.shadowRoot.querySelector('tbody').addEventListener('focus', event => {
      if (event.target.tagName === 'INPUT') {
        const rowIndex = event.target.closest('tr').rowIndex - 1;
        const colIndex = event.target.closest('td').cellIndex;
        const value = event.target.value;
        this.dispatchEvent(new CustomEvent('focused', { detail: { rowIndex, colIndex, value } }));
        if (this.hasAttribute('debug')) {
          console.log(`Cell focused: Row ${rowIndex}, Col ${colIndex}, Value ${value}`);
        }
      }
    }, true);

    this.shadowRoot.querySelector('tbody').addEventListener('keydown', event => {
      if (event.key === 'Backspace' && event.target.tagName === 'INPUT') {
        const input = event.target;
        const start = input.selectionStart;
        const end = input.selectionEnd;
        if (start === end && start > 0) {
          input.value = input.value.slice(0, start - 1) + input.value.slice(end);
          input.selectionStart = input.selectionEnd = start - 1;
          event.preventDefault();
        }
      }
    });
  }

  rowCount() {
    return this.shadowRoot.querySelector('tbody').rows.length;
  }

  columnCount() {
    return this.shadowRoot.querySelector('thead').rows[0].cells.length;
  }

  isEmptyRow(rowIndex) {
    const row = this.shadowRoot.querySelector(`tbody tr:nth-child(${rowIndex + 1})`);
    return Array.from(row.cells).every(cell => cell.querySelector('input').value === '');
  }

  appendRow() {
    const tbody = this.shadowRoot.querySelector('tbody');
    const row = document.createElement('tr');
    for (let i = 0; i < this.columnCount(); i++) {
      const td = document.createElement('td');
      const input = document.createElement('input');
      input.type = 'text';
      input.placeholder = this.getAttribute('placeholder') || '';
      const datalistId = `column-${i}`;
      const datalist = this.shadowRoot.querySelector(`datalist#${datalistId}`);
      if (datalist) {
        input.setAttribute('list', datalistId);
      }
      td.appendChild(input);
      row.appendChild(td);
    }
    tbody.appendChild(row);
    row.cells[0].querySelector('input').focus();
  }

  cleanupTable() {
    const tbody = this.shadowRoot.querySelector('tbody');
    const rows = tbody.rows;
    for (let i = rows.length - 1; i >= 0; i--) {
      if (this.isEmptyRow(i)) {
        tbody.deleteRow(i);
      }
    }
  }

  toCSV() {
    const rows = [];
    const tbody = this.shadowRoot.querySelector('tbody').rows;
    for (let i = 0; i < tbody.length; i++) {
      const cells = tbody[i].cells;
      const row = [];
      for (let j = 0; j < cells.length; j++) {
        row.push(cells[j].querySelector('input').value);
      }
      rows.push(row);
    }
    return stringifyCSV(rows);
  }

  fromCSV(csvText) {
    const rows = parseCSV(csvText);
    const tbody = this.shadowRoot.querySelector('tbody');
    tbody.innerHTML = '';
    rows.forEach(row => {
      const tr = document.createElement('tr');
      row.forEach(cell => {
        const td = document.createElement('td');
        const input = document.createElement('input');
        input.type = 'text';
        input.value = cell;
        td.appendChild(input);
        tr.appendChild(td);
      });
      tbody.appendChild(tr);
    });
  }

  toObjects() {
    const objects = [];
    const tbody = this.shadowRoot.querySelector('tbody').rows;
    for (let i = 0; i < tbody.length; i++) {
      const cells = tbody[i].cells;
      for (let j = 0; j < cells.length; j++) {
        objects.push({ rowIndex: i, colIndex: j, value: cells[j].querySelector('input').value });
      }
    }
    return objects;
  }

  fromObjects(objects) {
    const tbody = this.shadowRoot.querySelector('tbody');
    tbody.innerHTML = '';
    objects.forEach(obj => {
      let row = tbody.rows[obj.rowIndex];
      if (!row) {
        row = document.createElement('tr');
        tbody.appendChild(row);
      }
      let cell = row.cells[obj.colIndex];
      if (!cell) {
        cell = document.createElement('td');
        row.appendChild(cell);
      }
      let input = cell.querySelector('input');
      if (!input) {
        input = document.createElement('input');
        input.type = 'text';
        cell.appendChild(input);
      }
      input.value = obj.value;
    });
  }

  fromTextarea() {
    const textarea = this.querySelector('textarea');
    if (textarea) {
      this.fromCSV(textarea.value.trim());
    }
  }

  toTextarea() {
    const textarea = this.querySelector('textarea');
    if (textarea) {
      textarea.value = this.toCSV();
    }
  }

  getCellValue(rowIndex, colIndexOrName) {
    const colIndex = typeof colIndexOrName === 'number' ? colIndexOrName : this.getColumnIndexByName(colIndexOrName);
    const cell = this.shadowRoot.querySelector(`tbody tr:nth-child(${rowIndex + 1}) td:nth-child(${colIndex + 1}) input`);
    return cell ? cell.value : '';
  }

  setCellValue(rowIndex, colIndexOrName, value) {
    const colIndex = typeof colIndexOrName === 'number' ? colIndexOrName : this.getColumnIndexByName(colIndexOrName);
    const cell = this.shadowRoot.querySelector(`tbody tr:nth-child(${rowIndex + 1}) td:nth-child(${colIndex + 1}) input`);
    if (cell) {
      cell.value = value;
    }
  }

  toJSON() {
    return JSON.stringify(this.toObjects());
  }

  fromJSON(jsonString) {
    this.fromObjects(JSON.parse(jsonString));
  }

  setAutocomplete(colIndexOrName, options) {
    const colIndex = typeof colIndexOrName === 'number' ? colIndexOrName : this.getColumnIndexByName(colIndexOrName);
    const datalistId = `column-${colIndex}`;
    let datalist = this.shadowRoot.querySelector(`datalist#${datalistId}`);
    if (!datalist) {
      datalist = document.createElement('datalist');
      datalist.id = datalistId;
      this.shadowRoot.appendChild(datalist);
    }
    datalist.innerHTML = '';
    options.forEach(option => {
      const opt = document.createElement('option');
      opt.value = option.value;
      datalist.appendChild(opt);
    });
    const inputs = this.shadowRoot.querySelectorAll(`tbody td:nth-child(${colIndex + 1}) input`);
    inputs.forEach(input => input.setAttribute('list', datalistId));
  }

  getAutocomplete(colIndexOrName) {
    const colIndex = typeof colIndexOrName === 'number' ? colIndexOrName : this.getColumnIndexByName(colIndexOrName);
    const datalist = this.shadowRoot.querySelector(`datalist#column-${colIndex}`);
    if (datalist) {
      const options = [];
      datalist.querySelectorAll('option').forEach(option => {
        options.push({ value: option.value });
      });
      return options;
    }
    return undefined;
  }

  getColumnIndexByName(colName) {
    const headings = parseCSVRow(this.getAttribute('column-headings'));
    return headings.indexOf(colName);
  }
}

customElements.define('csv-textarea', CSVTextarea);

export { CSVTextarea };