/* global React */

function Counter({ value, max }) {
  const len = (value || "").length;
  const at = len >= max;
  return <span className={"counter" + (at ? " over" : "")}>{len}/{max}</span>;
}

function Label({ label, required, max, value }) {
  return (
    <div className="field-label">
      <span className="lbl">{label}{required ? <span className="req">*</span> : <span className="opt"> (optional)</span>}</span>
      {max ? <Counter value={value} max={max} /> : null}
    </div>
  );
}

// Hard-enforce the limit: slice anything past max (covers paste too).
function capped(v, max) {
  return max && v.length > max ? v.slice(0, max) : v;
}
function limitClass(value, max, error) {
  const at = max && (value || "").length >= max;
  return (error ? " invalid" : "") + (at ? " at-limit" : "");
}

function TextField({ label, value, onChange, max, required, error, hint, placeholder, type = "text", inputMode }) {
  return (
    <div className="field">
      <Label label={label} required={required} max={max} value={value} />
      <input
        className={"input" + limitClass(value, max, error)}
        type={type}
        inputMode={inputMode}
        value={value || ""}
        placeholder={placeholder}
        maxLength={max || undefined}
        onChange={(e) => onChange(capped(e.target.value, max))}
      />
      {error ? <div className="field-error">{error}</div> : hint ? <div className="field-hint">{hint}</div> : null}
    </div>
  );
}

function TextArea({ label, value, onChange, max, required, error, hint, placeholder, rows = 4 }) {
  return (
    <div className="field">
      <Label label={label} required={required} max={max} value={value} />
      <textarea
        className={"textarea" + limitClass(value, max, error)}
        value={value || ""}
        rows={rows}
        placeholder={placeholder}
        maxLength={max || undefined}
        onChange={(e) => onChange(capped(e.target.value, max))}
      />
      {error ? <div className="field-error">{error}</div> : hint ? <div className="field-hint">{hint}</div> : null}
    </div>
  );
}

function SelectField({ label, value, onChange, options, required, error, hint, placeholder }) {
  return (
    <div className="field">
      <Label label={label} required={required} value={value} />
      <select
        className={"select" + (error ? " invalid" : "")}
        value={value || ""}
        onChange={(e) => onChange(e.target.value)}
      >
        <option value="">{placeholder || "Select…"}</option>
        {options.map((o) => <option key={o} value={o}>{o}</option>)}
      </select>
      {error ? <div className="field-error">{error}</div> : hint ? <div className="field-hint">{hint}</div> : null}
    </div>
  );
}

function RangeField({ label, value, onChange, min = 0, max = 100, step = 5, suffix = "%", valueLabel }) {
  return (
    <div className="field">
      <div className="field-label"><span className="lbl">{label}</span></div>
      <div className="slider-row">
        <input type="range" min={min} max={max} step={step}
          value={value || 0} onChange={(e) => onChange(Number(e.target.value))} />
        <span className="slider-val">{valueLabel != null ? valueLabel : `${value || 0}${suffix}`}</span>
      </div>
    </div>
  );
}

// Bullet list editor: up to maxItems short lines, each hard-capped at max chars.
function BulletListField({ label, items, onChange, max, maxItems = 8, required, error, hint, placeholder }) {
  const list = (items && items.length ? items : [""]);
  function setAt(i, v) { const a = list.slice(); a[i] = capped(v, max); onChange(a); }
  function removeAt(i) { const a = list.filter((_, j) => j !== i); onChange(a.length ? a : [""]); }
  function add() { if (list.length < maxItems) onChange([...list, ""]); }
  return (
    <div className="field">
      <div className="field-label">
        <span className="lbl">{label}{required ? <span className="req">*</span> : <span className="opt"> (optional)</span>}</span>
        <span className="counter">{list.filter(b => b.trim()).length}/{maxItems} bullets</span>
      </div>
      <div className="bullet-list">
        {list.map((b, i) => (
          <div className="bullet-row" key={i}>
            <span className="bullet-dot" aria-hidden="true"></span>
            <input
              className={"input" + limitClass(b, max, false)}
              value={b}
              placeholder={placeholder}
              maxLength={max || undefined}
              onChange={(e) => setAt(i, e.target.value)}
            />
            <span className={"counter" + ((b || "").length >= max ? " over" : "")} style={{ flex: "0 0 auto" }}>{(b || "").length}/{max}</span>
            {list.length > 1 ? (
              <button type="button" className="icon-btn" title="Remove bullet" onClick={() => removeAt(i)}>✕</button>
            ) : null}
          </div>
        ))}
      </div>
      <button type="button" className="bullet-add" disabled={list.length >= maxItems} onClick={add}>
        + Add bullet{list.length >= maxItems ? " (limit reached)" : ""}
      </button>
      {error ? <div className="field-error">{error}</div> : hint ? <div className="field-hint">{hint}</div> : null}
    </div>
  );
}

function MonthYearField({ label, value, onChange, required, error, hint, disabled }) {
  // value stored as "Mon YYYY" string; input is type=month -> convert
  const MONTHS = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
  // parse current to yyyy-mm for the input
  let inputVal = "";
  if (value) {
    const m = value.match(/(\w{3})\s+(\d{4})/);
    if (m) {
      const mi = MONTHS.indexOf(m[1]);
      if (mi >= 0) inputVal = `${m[2]}-${String(mi + 1).padStart(2, "0")}`;
    }
  }
  return (
    <div className="field">
      <Label label={label} required={required} />
      <input
        className={"input" + (error ? " invalid" : "")}
        type="month"
        value={inputVal}
        disabled={disabled}
        style={disabled ? { opacity: .5 } : undefined}
        onChange={(e) => {
          const v = e.target.value;
          if (!v) { onChange(""); return; }
          const [y, mm] = v.split("-");
          onChange(`${MONTHS[Number(mm) - 1]} ${y}`);
        }}
      />
      {error ? <div className="field-error">{error}</div> : hint ? <div className="field-hint">{hint}</div> : null}
    </div>
  );
}

Object.assign(window, { TextField, TextArea, SelectField, RangeField, MonthYearField, BulletListField, Counter });
