import EditableInput from './EditableInput';

class LayoutTreeGridModel {
  constructor(root) {
    this.root = root;
    this.rootId = root.id;
  }

  setRoot(newRoot) {
    this.root = newRoot;
  }

  getNodePath(node, targetId, path = '') {
    // Check if the current node is the target node
    if (node.id === targetId) {
      return path;
    }

    // If the current node has children, iterate over them
    if (node.children) {
      for (let i = 0; i < node.children.length; i++) {
        // Construct the path to the current child
        const currentPath = path ? `${path}.children[${i}]` : `children[${i}]`;

        // Recursively call findPath on the child
        const resultPath = this.getNodePath(node.children[i], targetId, currentPath);

        // If resultPath is not null, the target has been found in the subtree
        if (resultPath) {
          return resultPath;
        }
      }
    }

    // Return null if the target is not found in this subtree
    return null;
  }
}

class LayoutTreeGridView {
  constructor(selector) {
    this.selector = selector;
    this.table = $('<table>').appendTo($(this.selector));
    this.table.addClass('layout_table');
    this.table.css({'width': 'inherit', 'border-collapse': 'collapse', 'border': '1px gray solid'});
    this.init();
  }

  init() {
    this.table.children().remove();
  }

  clear() {
    this.init();
  }

  addHeaders(fields) {
    const thead = $('<thead>').appendTo(this.table);
    const tr = $('<tr>').appendTo(thead);
    tr.addClass('layout-grid-row');

    fields.forEach(field => {
      const th = $('<th>').html(field.label).appendTo(tr);
      th.css({'width': field.width + 'px', 'border': '1px gray solid', 'text-align': 'center'});
    });
  }

  toggleChildrenVisibility(nodeId, isExpanded) {
    const selector = `.treegrid-parent-${nodeId}`;
    $(selector).each((_, el) => {
      $(el).toggle(!isExpanded);

      if (isExpanded) {  // If we are hiding the children
        const childNodeId = $(el).data('nodeId'); // Assume data-nodeId is set when rows are created
        this.toggleChildrenVisibility(childNodeId, true);  // Recursively hide all descendants
        const expander = $(`.treegrid-${nodeId} .treegrid-expander`);
        expander.html(isExpanded ? '+' : '-');
      }
    });
  }

  setupExpander(cell, callback) {
    const expander = $('<span>').addClass('treegrid-expander').html('-').appendTo(cell);
    expander.click(callback);
  }
}

class LayoutTreeGridController {
  constructor(model, view, options, callback) {
    this.model = model;
    this.view = view;
    this.options = options;
    this.callback = callback;
    this.init();
  }

  init() {
    this.view.init();
    this.view.addHeaders(this.options);
    this.processNode(this.model.root, 0);
    this.view.table.find('.editable').each((index, editableElement) => {
      const editableInput = new EditableInput({
        name: editableElement.dataset.name,
        value: editableElement.dataset.value,
        path: editableElement.dataset.path
      });

      editableInput.init(editableElement, async (value) => {
        _.set(this.model.root, editableElement.dataset.path, value);
        this.callback(this.model.root);
      });
    });
  }

  getIndent(depth) {
    return new Array(depth + 1).join('<span class="treegrid-indent"></span>');
  }

  addRow(node, depth) {
    // console.log('================================ addRow: ', node.id);
    const tr = $('<tr>').addClass('treegrid-' + node.id).data('nodeId', node.id);

    if (depth === 0) {
      tr.css({'display': 'none'});
    }

    if (node.parent !== undefined && node.parent !== null && parseInt(node.parent) !== this.model.rootId) {
      const parentSelector = `.treegrid-${node.parent}`;
      const lastChildSelector = `.treegrid-parent-${node.parent}`;

      if ($(this.view.table).find(lastChildSelector).length > 0) {
        const lastChild = $(this.view.table).find(lastChildSelector).last();
        tr.insertAfter(lastChild);
        // console.log('addRow, node: ', node.id, ' parent: ', node.parent, 'tr: ', tr, 'insertAfterLastChild: ', lastChild);
      } else {
        // console.log('addRow, node: ', node.id, ' parent: ', node.parent, 'tr: ', tr, 'insertAfterParent: ', parentSelector);
        tr.insertAfter($(this.view.table).find(parentSelector));
      }
      tr.addClass('treegrid-parent-' + node.parent);
    } else {
      tr.appendTo(this.view.table);
      // console.log('addRow, node: ', node.id, ' parent: ', node.parent, 'tr: ', tr, 'no parent');
    }

    // console.log('================================ row Added');
    return tr;
  }
  addCell(row, node, fieldInfo, depth) {
    const td = $('<td>').appendTo(row);
    const padding = fieldInfo.isFirst ? this.getIndent(depth) : '';
    const nodePath = this.model.getNodePath(this.model.root, node.id) + '.value';

    if (node.loutItemType === 'Field' && fieldInfo.type === 'textfield') {
      const div = $('<div>');
      div.addClass('editable');
      div.appendTo(td);
      div.attr('data-name', fieldInfo.name);
      div.attr('data-value', node[fieldInfo.name]);
      div.attr('data-path', nodePath);

    } else {
      td.html(padding); // Default to just displaying the content
    }

    if (fieldInfo.width) {
      td.css({'width': fieldInfo.width + 'px', 'border': '1px gray solid'});
    }

    if (fieldInfo.align) {
      td.css({'text-align': fieldInfo.align});
    }

    return td;
  }

  processNode(node, depth) {
    // console.log('node: ', node.id);
    const tr = this.addRow(node, depth);

    this.options.forEach((fieldInfo) => {
      const content = node[fieldInfo.name];
      const td = this.addCell(tr, node, fieldInfo, depth);

      if (fieldInfo.isFirst) {
        if (node.children && node.children.length > 0) {
          this.view.setupExpander($(tr.children()[0]), () => this.handleExpanderClick(node.id));
        }
      }

      if (fieldInfo.type !== 'textfield') {
        td.append(content);
      }
    });

    // Recursively process each child node if any
    if (node.children && node.children.length > 0) {
      node.children.forEach(child => {
        this.processNode(child, depth + 1); // Increment depth for each child
      });
    }
  }

  handleExpanderClick(nodeId) {
    const expander = $(`.treegrid-${nodeId} .treegrid-expander`);
    const isExpanded = expander.html() === '-';
    expander.html(isExpanded ? '+' : '-');
    this.view.toggleChildrenVisibility(nodeId, isExpanded);
  }

  rebuild(newRoot) {
    this.model.setRoot(newRoot);
    this.view.clear();
    this.init();
  }
}

class LayoutTreeGrid {
  constructor(selector, root, options, callback) {
    this.model = new LayoutTreeGridModel(root);
    this.view = new LayoutTreeGridView(selector);
    this.controller = new LayoutTreeGridController(this.model, this.view, options, callback);
  }

  rebuild(root, callback) {
    this.controller.rebuild(root);
    callback(root);
  }
}

export default LayoutTreeGrid;
