import { Combine, Layers, SlidersHorizontal, Trash2, Upload } from "lucide-react";

const REPEAT_SCHEMA = { type: "int", default: 1, min: 1, max: 20, step: 1, label: "N (times)" };

function defaultParams(operation) {
  return {
    _repeat: 1,
    ...Object.fromEntries(
      Object.entries(operation?.params || {}).map(([key, schema]) => [key, schema.default])
    )
  };
}

function groupOperations(operations) {
  return operations.reduce((acc, operation) => {
    acc[operation.chapter] ||= {};
    acc[operation.chapter][operation.slide_group] ||= [];
    acc[operation.chapter][operation.slide_group].push(operation);
    return acc;
  }, {});
}

function ParamControl({ name, schema, value, onChange }) {
  const label = schema.label || name;
  function parseNumeric(raw) {
    let next = schema.type === "int" ? parseInt(raw || schema.default, 10) : Number(raw);
    if (schema.type === "int" && schema.odd && next % 2 === 0) next += 1;
    if (Number.isFinite(schema.min)) next = Math.max(schema.min, next);
    if (Number.isFinite(schema.max)) next = Math.min(schema.max, next);
    return next;
  }
  if (schema.type === "select") {
    return (
      <label className="mb-3 block text-xs text-zinc-300">
        <span className="mb-1 block">{label}</span>
        <select className="w-full border border-zinc-700 bg-zinc-950 px-2 py-2 text-sm" value={value ?? schema.default} onChange={(event) => onChange(name, event.target.value)}>
          {schema.choices.map((choice) => (
            <option key={choice} value={choice}>{choice}</option>
          ))}
        </select>
        {schema.description ? <span className="mt-1 block text-[11px] leading-relaxed text-zinc-500">{schema.description}</span> : null}
      </label>
    );
  }
  if (schema.type === "bool") {
    return (
      <label className="mb-3 flex items-center gap-2 text-xs text-zinc-300">
        <input type="checkbox" checked={Boolean(value ?? schema.default)} onChange={(event) => onChange(name, event.target.checked)} />
        {label}
        {schema.description ? <span className="text-[11px] leading-relaxed text-zinc-500">{schema.description}</span> : null}
      </label>
    );
  }
  return (
    <label className="mb-4 block">
      <div className="mb-2 flex items-center justify-between text-xs text-zinc-300">
        <span>{label}{schema.odd ? " (odd)" : ""}</span>
        <input
          className="w-20 border border-zinc-700 bg-zinc-950 px-2 py-1 text-right tabular-nums"
          type="number"
          min={schema.min}
          max={schema.max}
          step={schema.step}
          value={value ?? schema.default}
          onChange={(event) => onChange(name, parseNumeric(event.target.value))}
        />
      </div>
      <input
        type="range"
        min={schema.min}
        max={schema.max}
        step={schema.step}
        value={value ?? schema.default}
        onChange={(event) => onChange(name, parseNumeric(event.target.value))}
        className="w-full accent-cyan-400"
      />
      {schema.description ? <span className="mt-1 block text-[11px] leading-relaxed text-zinc-500">{schema.description}</span> : null}
    </label>
  );
}

function shouldShowParam(schema, params) {
  if (!schema.show_when) return true;
  return params?.[schema.show_when.param] === schema.show_when.value;
}

export default function Controls({
  operations,
  selectedOperation,
  params,
  states,
  activeState,
  selectedStateIds,
  busy,
  onUpload,
  onSelectOperation,
  onParamChange,
  onApply,
  onSelectState,
  onToggleCombineState,
  onCombine,
  onDeleteState,
}) {
  const grouped = groupOperations(operations);
  const operation = operations.find((item) => item.id === selectedOperation);
  const combineActions = [
    ["add", "add"],
    ["subtract", "subtract"],
    ["dot_product", "dot product"],
    ["average", "average selected"],
    ["and", "and"],
    ["or", "or"]
  ];

  function renderMatrixPreview(matrix) {
    if (matrix.kernels) {
      return (
        <div key={matrix.title} className="border border-zinc-800 bg-zinc-900/70 p-2">
          <div className="mb-2 text-xs font-semibold text-cyan-200">{matrix.title}</div>
          <div className="grid grid-cols-2 gap-2">
            {matrix.kernels.map((kernel) => (
              <div key={kernel.label}>
                <div className="mb-1 text-[11px] text-zinc-400">{kernel.label}</div>
                <div className="grid w-max gap-1" style={{ gridTemplateColumns: `repeat(${kernel.matrix[0].length}, minmax(1.75rem, auto))` }}>
                  {kernel.matrix.flat().map((value, index) => (
                    <span key={index} className="border border-zinc-700 px-2 py-1 text-center text-xs tabular-nums text-zinc-200">{value}</span>
                  ))}
                </div>
              </div>
            ))}
          </div>
        </div>
      );
    }
    return (
      <div key={matrix.title} className="border border-zinc-800 bg-zinc-900/70 p-2">
        <div className="mb-1 text-xs font-semibold text-cyan-200">{matrix.title}{matrix.scale ? ` (${matrix.scale})` : ""}</div>
        <div className="grid w-max gap-1" style={{ gridTemplateColumns: `repeat(${matrix.matrix[0].length}, minmax(1.75rem, auto))` }}>
          {matrix.matrix.flat().map((value, index) => (
            <span key={index} className="border border-zinc-700 px-2 py-1 text-center text-xs tabular-nums text-zinc-200">{value}</span>
          ))}
        </div>
      </div>
    );
  }

  function renderCombineActions() {
    return (
      <div className="border border-zinc-800 bg-zinc-950/70 p-3">
        <div className="mb-2 flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.14em] text-cyan-200">
          <Combine size={14} />
          Arithmetic / Logic
        </div>
        <div className="grid grid-cols-2 gap-2">
          {combineActions.map(([kind, label]) => (
            <button key={kind} disabled={selectedStateIds.length < 2 || busy} onClick={() => onCombine(kind)} className="border border-zinc-700 bg-zinc-900 px-2 py-2 text-xs disabled:cursor-not-allowed disabled:opacity-40">
              {label}
            </button>
          ))}
        </div>
      </div>
    );
  }

  function renderParameterDrawer(item) {
    if (selectedOperation !== item.id) return null;
    const canApply = Boolean(activeState) && !busy;
    const visibleParams = Object.entries(item.params || {}).filter(([, schema]) => shouldShowParam(schema, params));
    return (
      <div className="border border-emerald-700 bg-zinc-950 p-3">
        <div className="mb-3 flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.14em] text-emerald-300">
          <SlidersHorizontal size={14} />
          Parameters
        </div>
        {item.formula ? <div className="mb-3 border border-zinc-800 bg-zinc-900/70 p-2 text-xs leading-relaxed text-zinc-300">{item.formula}</div> : null}
        {item.repeatable ? <ParamControl name="_repeat" schema={REPEAT_SCHEMA} value={params._repeat} onChange={onParamChange} /> : null}
        {visibleParams.map(([name, schema]) => (
          <ParamControl key={name} name={name} schema={schema} value={params[name]} onChange={onParamChange} />
        ))}
        {visibleParams.length === 0 ? <p className="mb-3 text-sm text-zinc-500">No operation-specific parameters.</p> : null}
        {item.matrices?.length ? (
          <div className="mb-3 space-y-2">
            {item.matrices.map(renderMatrixPreview)}
          </div>
        ) : null}
        <button disabled={!canApply} onClick={onApply} className="w-full border border-emerald-600 bg-emerald-950/60 px-3 py-2 text-sm font-semibold text-emerald-100 disabled:cursor-not-allowed disabled:opacity-40">
          Apply to Active State
        </button>
      </div>
    );
  }

  return (
    <aside className="flex h-screen w-[430px] shrink-0 flex-col overflow-hidden border-r border-zinc-800 bg-zinc-950">
      <div className="border-b border-zinc-800 px-5 py-4">
        <h1 className="text-lg font-semibold text-zinc-50">Image Processing Workspace</h1>
        <p className="mt-1 text-xs text-zinc-400">MATLAB-like states organized by lecture chapters</p>
      </div>

      <div className="space-y-3 border-b border-zinc-800 p-4">
        <label className="flex cursor-pointer items-center justify-center gap-2 border border-cyan-700 bg-cyan-950/60 px-3 py-2 text-sm font-medium text-cyan-100 hover:bg-cyan-900/60">
          <Upload size={16} />
          Upload Image
          <input type="file" accept="image/*" className="hidden" onChange={(event) => onUpload(event.target.files?.[0])} />
        </label>
      </div>

      <section className="border-b border-zinc-800 p-4">
        <div className="mb-2 flex items-center gap-2 text-sm font-semibold text-zinc-100">
          <Layers size={16} className="text-cyan-300" />
          Image States
        </div>
        <div className="max-h-48 space-y-2 overflow-y-auto">
          {states.length === 0 ? <p className="text-sm text-zinc-500">No states yet.</p> : states.map((state) => (
            <div key={state.state_id} className={`flex items-center gap-2 border p-2 ${activeState?.state_id === state.state_id ? "border-emerald-500 bg-emerald-950/30" : "border-zinc-800 bg-zinc-900"}`}>
              <input type="checkbox" checked={selectedStateIds.includes(state.state_id)} onChange={() => onToggleCombineState(state.state_id)} />
              <button className="min-w-0 flex-1 text-left" onClick={() => onSelectState(state)}>
                <div className="truncate text-sm text-zinc-100">{state.label}</div>
                <div className="truncate text-xs text-zinc-500">{state.width}x{state.height} - {state.operation}</div>
              </button>
              <button
                type="button"
                disabled={state.sequence === 0 || busy}
                onClick={() => onDeleteState(state)}
                className="border border-zinc-700 p-1.5 text-zinc-400 hover:border-red-500 hover:text-red-300 disabled:cursor-not-allowed disabled:opacity-30"
                title={state.sequence === 0 ? "S0 cannot be deleted" : `Delete ${state.label}`}
              >
                <Trash2 size={14} />
              </button>
            </div>
          ))}
        </div>
      </section>

      <div className="min-h-0 flex-1 overflow-y-auto p-4">
        {Object.entries(grouped).map(([chapter, groups]) => (
          <details key={chapter} open={chapter === "Basic" || chapter.includes("Chapter 3")} className="mb-3 border border-zinc-800 bg-zinc-900/60">
            <summary className="cursor-pointer px-3 py-3 text-sm font-semibold text-zinc-100">{chapter}</summary>
            <div className="space-y-3 border-t border-zinc-800 p-3">
              {chapter === "Basic" ? renderCombineActions() : null}
              {Object.entries(groups).map(([slideGroup, items]) => (
                <section key={slideGroup} className="border border-zinc-800 bg-zinc-950/70">
                  <div className="border-b border-zinc-800 px-3 py-2 text-xs font-semibold text-cyan-200">{slideGroup}</div>
                  <div className="grid grid-cols-1 gap-2 p-2">
                    {items.map((item) => (
                      <div key={item.id} className="space-y-2">
                        <button
                          disabled={!activeState || busy}
                          onClick={() => onSelectOperation(item.id, defaultParams(item))}
                          className={`w-full border px-3 py-2 text-left text-sm ${selectedOperation === item.id ? "border-emerald-500 bg-emerald-950/50 text-emerald-100" : "border-zinc-700 bg-zinc-900 text-zinc-200 hover:bg-zinc-800"} disabled:cursor-not-allowed disabled:opacity-40`}
                        >
                          {item.label}
                        </button>
                        {renderParameterDrawer(item)}
                      </div>
                    ))}
                  </div>
                </section>
              ))}
            </div>
          </details>
        ))}
      </div>

      {operation ? null : <div className="border-t border-zinc-800 bg-zinc-950 p-4 text-sm text-zinc-500">Select an operation.</div>}
    </aside>
  );
}
