import React, { useState, useEffect, useCallback } from 'react';
import { cn } from "@/lib/utils";
import EditableInput from '../shared/EditableInput';
import _ from 'lodash';
import APIClient from '@/services/APIClient.js';

// Helper function to get indentation for tree visualization
const getIndent = (depth) => {
  return Array(depth + 1).fill().map((_, i) => (
      <span key={i} className="treegrid-indent" />
  ));
};

const TreeNode = ({
  node,
  depth,
  options,
  isFirst,
  onExpand,
  expanded,
  onValueChange,
  getNodePath
}) => {
  const hasChildren = node.children && node.children.length > 0;

  const renderCell = (fieldInfo) => {
    const padding = fieldInfo.isFirst ? getIndent(depth) : null;
    const nodePath = getNodePath(node.id) + '.value';

    if (node.loutItemType === 'Field' && fieldInfo.type === 'textfield') {
      return (
          <EditableInput
              name={fieldInfo.name}
              value={node[fieldInfo.name] || ''}
              onChange={(value) => onValueChange(nodePath, value)}
          />
      );
    }

    return (
        <div className="flex items-center">
          {padding}
          {fieldInfo.isFirst && hasChildren && (
              <button
                  onClick={() => onExpand(node.id)}
                  className="treegrid-expander w-4 h-4 flex items-center justify-center"
              >
                {expanded ? '-' : '+'}
              </button>
          )}
          {node[fieldInfo.name]}
        </div>
    );
  };

  return (
      <tr className={`treegrid-${node.id} ${node.parent ? `treegrid-parent-${node.parent}` : ''}`}>
        {options.map((fieldInfo, index) => (
            <td
                key={fieldInfo.name}
                className={cn(
                    "border p-2",
                    fieldInfo.align === 'center' && "text-center",
                    fieldInfo.align === 'right' && "text-right"
                )}
                style={{ width: fieldInfo.width }}
            >
              {renderCell(fieldInfo)}
            </td>
        ))}
      </tr>
  );
};

const LayoutTreeDataGrid = ({
  root,
  apiRequest,
  options,
  totalMessageLengthSelector,
  onUpdate
}) => {
  const [expandedNodes, setExpandedNodes] = useState(new Set());
  const [apiClient] = useState(() => new APIClient());

  const getNodePath = useCallback((targetId, node = root, path = '') => {
    if (node.id === targetId) return path;

    if (node.children) {
      for (let i = 0; i < node.children.length; i++) {
        const currentPath = path ? `${path}.children[${i}]` : `children[${i}]`;
        const resultPath = getNodePath(targetId, node.children[i], currentPath);
        if (resultPath) return resultPath;
      }
    }
    return null;
  }, [root]);

  const handleExpand = useCallback((nodeId) => {
    setExpandedNodes(prev => {
      const next = new Set(prev);
      if (next.has(nodeId)) {
        next.delete(nodeId);
      } else {
        next.add(nodeId);
      }
      return next;
    });
  }, []);

  const fillPadding = useCallback(async (value, dataLength) => {
    let paddedValue = await apiClient.processPreScriptAndVariables(apiRequest, value.toString());
    while (paddedValue.length < dataLength) {
      paddedValue = ' ' + paddedValue;
    }
    return paddedValue;
  }, [apiRequest]);

  const concatenateFieldValues = useCallback(async (node) => {
    let concatenatedValues = '';

    if (node.loutItemType === 'Field') {
      concatenatedValues += await fillPadding(node.value || '', node.loutItemLength) || '';
    }

    if (node.children?.length > 0) {
      for (const child of node.children) {
        concatenatedValues += await concatenateFieldValues(child);
      }
    }

    return concatenatedValues;
  }, [fillPadding]);

  const sumFieldLoutItemLengths = useCallback(() => {
    const queue = [root];
    let sum = 0;

    while (queue.length > 0) {
      const node = queue.shift();
      if (node.loutItemType === 'Field') {
        sum += parseInt(node.loutItemLength) || 0;
      }
      if (node.children?.length > 0) {
        queue.push(...node.children);
      }
    }

    return sum;
  }, [root]);

  const handleValueChange = useCallback(async (path, value) => {
    _.set(root, path, value);
    const finalMessage = await concatenateFieldValues(root);
    onUpdate?.(finalMessage, root);
  }, [root, concatenateFieldValues, onUpdate]);

  useEffect(() => {
    if (totalMessageLengthSelector) {
      totalMessageLengthSelector.textContent = sumFieldLoutItemLengths();
    }
  }, [root, sumFieldLoutItemLengths, totalMessageLengthSelector]);

  const renderNodes = useCallback((node, depth = 0) => {
    const isExpanded = expandedNodes.has(node.id);
    const result = [];

    result.push(
        <TreeNode
            key={node.id}
            node={node}
            depth={depth}
            options={options}
            isFirst={true}
            onExpand={handleExpand}
            expanded={isExpanded}
            onValueChange={handleValueChange}
            getNodePath={getNodePath}
        />
    );

    if (isExpanded && node.children?.length > 0) {
      node.children.forEach(child => {
        result.push(...renderNodes(child, depth + 1));
      });
    }

    return result;
  }, [expandedNodes, options, handleExpand, handleValueChange, getNodePath]);

  return (
      <div className="overflow-auto">
        <table className="w-full border-collapse border">
          <thead>
          <tr>
            {options.map(field => (
                <th
                    key={field.name}
                    className="border p-2 text-center"
                    style={{ width: field.width }}
                >
                  {field.label}
                </th>
            ))}
          </tr>
          </thead>
          <tbody>
          {renderNodes(root)}
          </tbody>
        </table>
      </div>
  );
};

export default LayoutTreeDataGrid;
