import type { ReactNode } from 'react';
import { Plus, Trash2 } from 'lucide-react';

import { Button, Checkbox, Input, Label, RadioGroup, RadioGroupItem, Textarea } from '@ump/shared';

import {
  emptyRow,
  shouldShow,
  type ColumnDef,
  type FieldDef,
  type FormValues,
  type RepeatableDef,
  type RepeatableRow,
} from './proposalSchema';

type ChangeFn = (key: string, value: string | string[]) => void;

function ReqStar({ required }: { required?: boolean }) {
  return required ? <span className="ml-0.5 text-destructive">*</span> : null;
}

export function FieldControl({
  field,
  fullKey,
  value,
  error,
  onChange,
}: {
  field: FieldDef;
  fullKey: string;
  value: string | string[] | undefined;
  error?: boolean;
  onChange: ChangeFn;
}) {
  const id = 'f_' + fullKey.replace(/\W/g, '_');

  if (field.type === 'radio') {
    return (
      <div className="mb-4">
        <Label className="mb-1.5 block text-sm font-semibold">
          {field.label}
          <ReqStar required={field.required} />
        </Label>
        {field.hint && <p className="mb-1.5 text-xs text-muted-foreground">{field.hint}</p>}
        <RadioGroup
          className="gap-2"
          value={typeof value === 'string' ? value : ''}
          onValueChange={(v) => onChange(fullKey, v)}
        >
          {field.options?.map((o) => (
            <div key={o.value} className="flex items-center gap-2">
              <RadioGroupItem value={o.value} id={`${id}_${o.value}`} />
              <Label htmlFor={`${id}_${o.value}`} className="cursor-pointer text-sm font-normal">
                {o.label}
              </Label>
            </div>
          ))}
        </RadioGroup>
      </div>
    );
  }

  if (field.type === 'checkboxGroup') {
    const arr = Array.isArray(value) ? value : [];
    return (
      <div className="mb-4">
        <Label className="mb-1.5 block text-sm font-semibold">
          {field.label}
          <ReqStar required={field.required} />
        </Label>
        <div className="flex flex-col gap-2">
          {field.options?.map((o) => (
            <label key={o.value} className="flex cursor-pointer items-center gap-2 text-sm">
              <Checkbox
                checked={arr.includes(o.value)}
                onCheckedChange={(c) =>
                  onChange(fullKey, c === true ? [...arr, o.value] : arr.filter((x) => x !== o.value))
                }
              />
              <span>{o.label}</span>
            </label>
          ))}
        </div>
      </div>
    );
  }

  const labelEl = (
    <Label htmlFor={id} className="mb-1 block text-sm font-semibold">
      {field.label}
      <ReqStar required={field.required} />
    </Label>
  );
  const text = typeof value === 'string' ? value : '';

  if (field.type === 'textarea') {
    return (
      <div className="mb-4">
        {labelEl}
        {field.hint && <p className="mb-1.5 text-xs text-muted-foreground">{field.hint}</p>}
        <Textarea
          id={id}
          className={'min-h-24' + (error ? ' border-destructive' : '')}
          value={text}
          onChange={(e) => onChange(fullKey, e.target.value)}
        />
        {error && <p className="mt-1 text-xs text-destructive">Bắt buộc nhập.</p>}
      </div>
    );
  }

  const htmlType =
    field.type === 'number'
      ? 'number'
      : field.type === 'email'
        ? 'email'
        : field.type === 'tel'
          ? 'tel'
          : field.type === 'date'
            ? 'date'
            : 'text';

  return (
    <div className="mb-4">
      {labelEl}
      {field.hint && <p className="mb-1.5 text-xs text-muted-foreground">{field.hint}</p>}
      <Input
        id={id}
        type={htmlType}
        min={field.min}
        className={error ? 'border-destructive' : ''}
        value={text}
        onChange={(e) => onChange(fullKey, e.target.value)}
      />
      {error && <p className="mt-1 text-xs text-destructive">Bắt buộc nhập.</p>}
    </div>
  );
}

/** Render a flat list of fields, grouping consecutive `inline` fields onto one row. */
export function FieldList({
  fields,
  prefix,
  values,
  errors,
  onChange,
}: {
  fields: FieldDef[];
  prefix?: string;
  values: FormValues;
  errors: Set<string>;
  onChange: ChangeFn;
}) {
  const out: ReactNode[] = [];
  let buf: FieldDef[] = [];
  const renderOne = (f: FieldDef) => {
    const k = prefix ? `${prefix}.${f.key}` : f.key;
    const v = values[k];
    return (
      <FieldControl
        key={k}
        field={f}
        fullKey={k}
        value={Array.isArray(v) ? (v as string[]) : (v as string | undefined)}
        error={errors.has(k)}
        onChange={onChange}
      />
    );
  };
  const flush = () => {
    if (!buf.length) return;
    out.push(
      <div className="flex flex-wrap gap-4" key={`row_${buf[0].key}`}>
        {buf.map((f) => (
          <div className="min-w-40 flex-1" key={f.key}>
            {renderOne(f)}
          </div>
        ))}
      </div>,
    );
    buf = [];
  };
  for (const f of fields) {
    if (!shouldShow(f, values)) continue;
    if (f.inline) buf.push(f);
    else {
      flush();
      out.push(renderOne(f));
    }
  }
  flush();
  return <>{out}</>;
}

export function Repeatable({
  rep,
  rows,
  onRows,
}: {
  rep: RepeatableDef;
  rows: RepeatableRow[];
  onRows: (key: string, rows: RepeatableRow[]) => void;
}) {
  const update = (i: number, ck: string, val: string) =>
    onRows(rep.key, rows.map((r, idx) => (idx === i ? { ...r, [ck]: val } : r)));
  const add = () => onRows(rep.key, [...rows, emptyRow(rep.columns)]);
  const remove = (i: number) => onRows(rep.key, rows.filter((_, idx) => idx !== i));

  return (
    <div className="my-5">
      <h3 className="mb-2.5 text-sm font-semibold text-foreground">{rep.title}</h3>
      {rows.map((row, i) => (
        <div key={i} className="mb-3 rounded-lg border border-border bg-muted/30 p-4">
          <div className="mb-2.5 flex items-center justify-between text-xs font-semibold text-muted-foreground">
            <span>
              {rep.rowLabel} {i + 1}
            </span>
            {rows.length > rep.minRows && (
              <button
                type="button"
                className="inline-flex items-center gap-1 text-destructive hover:underline disabled:opacity-50"
                onClick={() => remove(i)}
              >
                <Trash2 className="h-3.5 w-3.5" /> Xóa
              </button>
            )}
          </div>
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
            {rep.columns.map((c: ColumnDef) => {
              const cid = `r_${rep.key}_${i}_${c.key}`;
              return (
                <div key={c.key}>
                  <Label htmlFor={cid} className="mb-1 block text-sm font-medium">
                    {c.label}
                  </Label>
                  {c.type === 'textarea' ? (
                    <Textarea
                      id={cid}
                      className="min-h-20"
                      value={row[c.key] ?? ''}
                      onChange={(e) => update(i, c.key, e.target.value)}
                    />
                  ) : (
                    <Input
                      id={cid}
                      type={c.type === 'number' ? 'number' : 'text'}
                      value={row[c.key] ?? ''}
                      onChange={(e) => update(i, c.key, e.target.value)}
                    />
                  )}
                </div>
              );
            })}
          </div>
        </div>
      ))}
      <Button type="button" variant="outline" size="sm" onClick={add}>
        <Plus className="mr-1.5 h-4 w-4" /> {rep.addLabel}
      </Button>
    </div>
  );
}
