import React, { CSSProperties } from 'react';
import { useNode, Element, UserComponent } from '@craftjs/core';
import { Container } from './Container';
import { cssPropsToString } from '../../utils/style-helpers';
import { escapeAttr, scopeId, cssValue } from '../../utils/escape';

type SplitOption =
  | '100'
  | '50-50' | '30-70' | '70-30' | '40-60' | '60-40'
  | '33-33-33' | '25-50-25'
  | '25-25-25-25'
  | '20-20-20-20-20'
  | '16-16-16-16-16-16'
  | 'equal';

interface ColumnLayoutProps {
  columns?: number;
  split?: SplitOption;
  gap?: string;
  style?: CSSProperties;
  children?: React.ReactNode;
  anchorId?: string;
}

const splitToWidths: Record<string, string[]> = {
  '100': ['100%'],
  '50-50': ['50%', '50%'],
  '30-70': ['30%', '70%'],
  '70-30': ['70%', '30%'],
  '40-60': ['40%', '60%'],
  '60-40': ['60%', '40%'],
  '33-33-33': ['33.333%', '33.333%', '33.333%'],
  '25-50-25': ['25%', '50%', '25%'],
  '25-25-25-25': ['25%', '25%', '25%', '25%'],
  '20-20-20-20-20': ['20%', '20%', '20%', '20%', '20%'],
  '16-16-16-16-16-16': ['16.666%', '16.666%', '16.666%', '16.666%', '16.666%', '16.666%'],
};

function getWidths(split: SplitOption, columns: number): string[] {
  // Check predefined splits first
  if (split !== 'equal') {
    const defined = splitToWidths[split];
    if (defined && defined.length === columns) return defined;
  }

  // Try parsing custom split string (e.g., "35-65" or "25-50-25")
  if (split && split !== 'equal' && split.includes('-')) {
    const parts = split.split('-').map(Number);
    if (parts.length === columns && parts.every(n => !isNaN(n) && n > 0)) {
      return parts.map(n => `${n}%`);
    }
  }

  // Fallback: equal widths
  const w = `${(100 / columns).toFixed(3)}%`;
  return Array.from({ length: columns }, () => w);
}

export const ColumnLayout: UserComponent<ColumnLayoutProps> = ({
  columns = 2,
  split = '50-50',
  gap = '16px',
  style = {},
  anchorId,
}) => {
  const { connectors: { connect, drag } } = useNode();
  const widths = getWidths(split, columns);

  return (
    <div
      ref={(ref: HTMLElement | null): void => { if (ref) connect(drag(ref)); }}
      id={anchorId || undefined}
      style={{
        display: 'flex',
        flexWrap: 'wrap',
        gap,
        width: '100%',
        minHeight: '60px',
        ...style,
      }}
    >
      {widths.map((w, i) => (
        <Element
          key={`col-${i}`}
          id={`col-${i}`}
          is={Container}
          canvas
          custom={{ className: 'craft-column' }}
          style={{ flex: `0 0 calc(${w} - ${gap})`, minHeight: '60px', padding: '8px' }}
          tag="div"
        />
      ))}
    </div>
  );
};

/* ---------- Craft config ---------- */

ColumnLayout.craft = {
  displayName: 'Columns',
  props: {
    columns: 2,
    split: '50-50',
    gap: '16px',
    style: {},
    anchorId: '',
  },
  rules: {
    canDrag: () => true,
    canMoveIn: () => false,
    canMoveOut: () => true,
  },
};

/* ---------- HTML export ---------- */

(ColumnLayout as any).toHtml = (props: ColumnLayoutProps, childrenHtml: string, nodeId?: string) => {
  const columns = props.columns || 2;
  const split = props.split || '50-50';
  // Sanitized once here so BOTH the raw <style> nth-child rule below AND the
  // cssPropsToString-built outerStyle get a safe value -- gap is a raw
  // string-interpolation sink into a <style> block (worst case: </style>
  // breakout -> arbitrary <script>), see task-cssxss-brief.md.
  const gap = cssValue(props.gap) || '16px';
  const widths = getWidths(split, columns);

  const outerStyle = cssPropsToString({
    display: 'flex',
    flexWrap: 'wrap',
    gap,
    width: '100%',
    ...props.style,
  });
  const idAttr = props.anchorId ? ` id="${escapeAttr(props.anchorId)}"` : '';

  // Each column is exported as an independently-serialized child node, so
  // toHtml has no direct handle on individual children to rewrite their
  // inline flex-basis. Instead, scope an nth-child CSS rule (with
  // !important, to win over any stale inline flex baked into a child at
  // creation time) to a generated class -- same width mapping (getWidths)
  // the editor render uses. Precedent: Menu/Navbar toHtml already emit
  // scoped <style> blocks for hover CSS. The class is scoped on the Craft
  // node id so two ColumnLayout instances with identical columns/split/gap
  // don't collide on the same class and cross-apply each other's widths.
  const scope = scopeId(nodeId, `${columns}:${split}:${gap}`, 'cols');
  const widthCss = widths
    .map((w, i) => `.${scope} > :nth-child(${i + 1}) { flex: 0 0 calc(${w} - ${gap}) !important; }`)
    .join('\n  ');

  return {
    html: `<style>\n  ${widthCss}\n</style>\n<div class="${scope}"${idAttr}${outerStyle ? ` style="${outerStyle}"` : ''}>${childrenHtml}</div>`,
  };
};
