'use client';

/**
 * One question: option rows, a synthetic "Other" row, and the free-text field
 * that appears ONLY while the Other row is engaged (or for text-mode
 * questions, where the text IS the answer). No always-on textarea — the exact
 * overload the 2026-07-22 design review called out.
 */

import { type ChangeEvent } from 'react';
import { Checkbox, RadioGroup, RadioGroupItem, Textarea } from '@djangocfg/ui-core';
import { cn } from '@djangocfg/ui-core/lib';
import { OTHER_MAX_LENGTH, useQuestionnaireContext } from './context';
import type { QuestionnaireOption, QuestionnaireQuestion } from './types';

const OTHER_ROW_VALUE = '__questionnaire_other__';

function rowClass(small: boolean): string {
  return cn(
    'flex cursor-pointer items-start gap-2 rounded-md hover:bg-muted/50',
    small ? 'min-h-7 px-1.5 py-0.5' : 'min-h-8 px-2 py-1',
  );
}

function OptionBody({ option, recommended }: { option: QuestionnaireOption; recommended: boolean }) {
  const { labels, small } = useQuestionnaireContext();
  return (
    <span className="min-w-0 flex-1">
      <span className={cn('flex flex-wrap items-center gap-1.5 text-foreground', small ? 'text-[13px]' : 'text-sm')}>
        <span>{option.label}</span>
        {recommended ? (
          <span className="rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium text-primary">
            {labels.recommended}
          </span>
        ) : null}
      </span>
      {option.description ? (
        <span className={cn('block text-muted-foreground', small ? 'text-[11px]' : 'text-xs')}>
          {option.description}
        </span>
      ) : null}
    </span>
  );
}

function OtherText({ question, autoFocus }: { question: QuestionnaireQuestion; autoFocus?: boolean }) {
  const { draft, busy, labels, small, onOtherChange } = useQuestionnaireContext();
  const isText = question.mode === 'text';
  const id = `${question.id}-other`;
  const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) =>
    onOtherChange(question.id, event.currentTarget.value);
  return (
    <div className={cn('space-y-1', isText ? undefined : cn('pt-0.5', small ? 'pl-7' : 'pl-8'))}>
      <label htmlFor={id} className="sr-only">
        {isText ? labels.yourAnswer : labels.otherAnswer}
      </label>
      <Textarea
        id={id}
        value={draft.other[question.id] ?? ''}
        disabled={busy}
        rows={isText ? 2 : 1}
        autoFocus={autoFocus}
        placeholder={isText ? labels.textPlaceholder : labels.otherPlaceholder}
        maxLength={OTHER_MAX_LENGTH}
        className={small ? 'min-h-8 text-[13px]' : undefined}
        onChange={handleChange}
      />
    </div>
  );
}

export function QuestionField({ question }: { question: QuestionnaireQuestion }) {
  const ctx = useQuestionnaireContext();
  const { busy, labels, small, draft } = ctx;

  if (question.mode === 'text') {
    return (
      <div className={small ? 'space-y-1' : 'space-y-1.5'}>
        <p className={cn('text-foreground', small ? 'text-[13px]' : 'text-sm')}>{question.prompt}</p>
        <OtherText question={question} />
      </div>
    );
  }

  const selected = draft.selectedIds[question.id] ?? [];
  const engaged = ctx.otherEngaged(question);
  const options = question.options ?? [];
  const multi = question.mode === 'multiple_choice';
  const maxPick = multi
    ? question.maxSelections ?? options.length + (question.allowOther ? 1 : 0)
    : 1;
  const otherCounts = engaged ? 1 : 0;
  const maxReached = multi && selected.length + otherCounts >= maxPick;

  const optionRows = options.map((option, index) => {
    const checked = selected.includes(option.id);
    const descriptionId = option.description ? `${question.id}-${index}-description` : undefined;
    const body = <OptionBody option={option} recommended={option.id === question.recommendedOptionId} />;
    if (multi) {
      const toggle = () => ctx.pickOption(question, option.id);
      return (
        <label key={option.id} className={rowClass(small)}>
          <Checkbox
            checked={checked}
            disabled={busy || (maxReached && !checked)}
            aria-describedby={descriptionId}
            onCheckedChange={toggle}
          />
          {body}
        </label>
      );
    }
    return (
      <label key={option.id} className={rowClass(small)}>
        <RadioGroupItem value={option.id} disabled={busy} aria-describedby={descriptionId} />
        {body}
      </label>
    );
  });

  const otherLabel = (
    <span className={cn('min-w-0 flex-1 text-foreground', small ? 'text-[13px]' : 'text-sm')}>
      {labels.otherAnswer}
    </span>
  );
  const otherRow = question.allowOther ? (
    multi ? (
      <label key={OTHER_ROW_VALUE} className={rowClass(small)}>
        <Checkbox
          checked={engaged}
          disabled={busy || (maxReached && !engaged)}
          onCheckedChange={() => (engaged ? ctx.disengageOther(question) : ctx.engageOther(question))}
        />
        {otherLabel}
      </label>
    ) : (
      <label key={OTHER_ROW_VALUE} className={rowClass(small)}>
        <RadioGroupItem value={OTHER_ROW_VALUE} disabled={busy} />
        {otherLabel}
      </label>
    )
  ) : null;

  const radioValue = engaged && question.allowOther ? OTHER_ROW_VALUE : selected[0] ?? '';
  const handleRadio = (value: string) =>
    value === OTHER_ROW_VALUE ? ctx.engageOther(question) : ctx.pickOption(question, value);

  const hint = multi ? (
    <p className="text-[11px] text-muted-foreground">
      {labels.selectionRange(question.minSelections ?? (question.required ? 1 : 0), maxPick)}
    </p>
  ) : null;

  return (
    <div className={small ? 'space-y-1' : 'space-y-1.5'}>
      <p className={cn('text-foreground', small ? 'text-[13px]' : 'text-sm')}>{question.prompt}</p>
      {multi ? (
        <div className="space-y-0.5">
          {optionRows}
          {otherRow}
        </div>
      ) : (
        <RadioGroup
          value={radioValue}
          onValueChange={handleRadio}
          aria-label={question.header || question.prompt}
          className="space-y-0.5"
        >
          {optionRows}
          {otherRow}
        </RadioGroup>
      )}
      {hint}
      {engaged && question.allowOther ? <OtherText question={question} autoFocus /> : null}
    </div>
  );
}
