import React, { useState, useEffect } from 'react';
import { format } from 'date-fns';
import Button from './ui/Button';
import { Input, Textarea } from './ui/FormField';
import Alert from './ui/Alert';
import { dailyStatusesApi, experimentsApi } from '../api/client';

const BUILTIN_KEYS = new Set(['experiment_description', 'vitals', 'treatment', 'notes']);
const EMPTY_TEMPLATE = [];

// Maps field width % to a 12-column grid span
function widthToSpan(pct) {
  if (pct <= 8)  return 1;
  if (pct <= 17) return 2;
  if (pct <= 25) return 3;
  if (pct <= 33) return 4;
  if (pct <= 42) return 5;
  if (pct <= 50) return 6;
  if (pct <= 67) return 8;
  if (pct <= 75) return 9;
  return 12;
}

/** Extract the value for a field from a status record.
 *  Custom fields are keyed by fieldId (stable UUID), not by key (display slug). */
function getValue(status, field) {
  if (!status) return '';
  if (field.builtin) return status[field.key] ?? '';
  return status.custom_fields?.[field.fieldId] ?? '';
}

export default function DailyStatusForm({ existing, animalId, experimentId, template = EMPTY_TEMPLATE, onTemplateUpdate, onSuccess, onCancel, onRequestDelete, hasPrev, hasNext, onNavigate }) {
  const today = format(new Date(), 'yyyy-MM-dd');

  // Active fields from template (date is always first and handled separately)
  const activeFields = template.filter((f) => f.active);

  function buildInitialValues() {
    const vals = { date: existing ? String(existing.date).slice(0, 10) : today };
    for (const f of activeFields) {
      vals[f.key] = getValue(existing, f);
    }
    return vals;
  }

  const [values, setValues] = useState(buildInitialValues);
  const [errors, setErrors] = useState({});
  const [apiError, setApiError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [savingTagFor, setSavingTagFor] = useState(null); // fieldId currently being saved

  useEffect(() => {
    setValues(buildInitialValues());
    setErrors({});
    setApiError(null);
  }, [existing, template]);

  const set = (key) => (e) => setValues((v) => ({ ...v, [key]: e.target.value }));

  async function saveTag(field) {
    const value = (values[field.key] ?? '').trim();
    if (!value || !experimentId || !onTemplateUpdate) return;
    setSavingTagFor(field.fieldId);
    try {
      const updatedTemplate = template.map((f) =>
        f.fieldId === field.fieldId
          ? { ...f, tags: [...(f.tags ?? []), value] }
          : f
      );
      await experimentsApi.updateTemplate(experimentId, updatedTemplate);
      onTemplateUpdate(updatedTemplate);
    } catch (err) {
      // non-critical — silently ignore tag save errors
    } finally {
      setSavingTagFor(null);
    }
  }

  function validate() {
    const e = {};
    if (!values.date) {
      e.date = 'Date is required';
    } else if (!/^\d{4}-\d{2}-\d{2}$/.test(values.date) || isNaN(new Date(values.date).getTime())) {
      e.date = 'Date must be a valid YYYY-MM-DD date';
    }
    setErrors(e);
    return Object.keys(e).length === 0;
  }

  async function doSave() {
    const builtin = {};
    const custom = {};
    for (const f of activeFields) {
      const val = values[f.key] || null;
      if (f.builtin) {
        builtin[f.key] = val;
      } else {
        custom[f.fieldId] = val;
      }
    }
    const existingCustom = existing?.custom_fields ?? {};
    const mergedCustom = { ...existingCustom, ...custom };
    const payload = { date: values.date, ...builtin, custom_fields: mergedCustom };
    return existing
      ? await dailyStatusesApi.update(existing.id, payload)
      : await dailyStatusesApi.create({ ...payload, animal_id: animalId });
  }

  async function handleSubmit(e) {
    e.preventDefault();
    if (!validate()) return;
    setLoading(true);
    setApiError(null);
    try {
      onSuccess(await doSave());
    } catch (err) {
      setApiError(err);
    } finally {
      setLoading(false);
    }
  }

  async function handleNavigate(direction) {
    if (!validate()) return;
    setLoading(true);
    setApiError(null);
    try {
      const result = await doSave();
      onNavigate(direction, result);
    } catch (err) {
      setApiError(err);
    } finally {
      setLoading(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} noValidate>
      {apiError && (
        <Alert type="error" message={apiError.message} details={apiError.details} onDismiss={() => setApiError(null)} />
      )}

      <div className="grid grid-cols-12 gap-x-3 gap-y-2 mb-4">
        {/* Date — always full width */}
        <div className="col-span-12 flex items-center gap-2">
          <label htmlFor="date" className="text-xs font-medium text-gray-500 whitespace-nowrap w-28 shrink-0 text-right">Date <span className="text-red-400">*</span></label>
          <div className="w-36">
            <Input type="date" name="date" value={values.date} onChange={set('date')} required disabled={loading} />
            {errors.date && <p role="alert" className="text-xs text-red-500 mt-0.5">{errors.date}</p>}
          </div>
        </div>

        {/* Dynamic fields */}
        {activeFields.map((field) => {
          const isTextarea = field.type === 'textarea';
          const span = isTextarea ? 12 : widthToSpan(field.width ?? 100);
          const fieldTags = field.tags ?? [];
          const currentValue = (values[field.key] ?? '').trim();
          const canSaveTag = experimentId && onTemplateUpdate && currentValue && !fieldTags.includes(currentValue) && !field.tagsDisabled;
          return (
            <div key={field.key} className={`col-span-${span} flex items-start gap-2`}>
              <label htmlFor={field.key} className="text-xs font-medium text-gray-500 whitespace-nowrap w-28 shrink-0 text-right pt-1.5" title={field.label}>
                {field.abbr || field.label}{field.unit ? <span className="font-normal text-gray-400"> ({field.unit})</span> : null}
              </label>
              <div className="flex-1 min-w-0">
                {isTextarea ? (
                  <Textarea name={field.key} value={values[field.key] ?? ''} onChange={set(field.key)} disabled={loading} />
                ) : (
                  <Input name={field.key} value={values[field.key] ?? ''} onChange={set(field.key)} disabled={loading} />
                )}
                {(fieldTags.length > 0 || canSaveTag) && (
                  <div className="flex flex-wrap items-center gap-1.5 mt-1">
                    {fieldTags.map((tag) => (
                      <button key={tag} type="button" title={`Quick-fill: ${tag}`}
                        onClick={() => setValues((v) => ({ ...v, [field.key]: tag }))}
                        className="inline-flex items-center px-2 py-0.5 rounded-full bg-indigo-50 border border-indigo-200 text-indigo-700 text-xs font-medium hover:bg-indigo-100 transition-colors">
                        {tag}
                      </button>
                    ))}
                    {canSaveTag && (
                      <button type="button" onClick={() => saveTag(field)} disabled={savingTagFor === field.fieldId}
                        title="Save current value as a quick-fill tag"
                        className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full border border-dashed border-indigo-300 text-indigo-500 text-xs hover:border-indigo-500 hover:text-indigo-700 transition-colors disabled:opacity-50">
                        {savingTagFor === field.fieldId ? '…' : '+ Save as tag'}
                      </button>
                    )}
                  </div>
                )}
              </div>
            </div>
          );
        })}
      </div>

      {activeFields.length === 0 && (
        <p className="text-sm text-gray-400 italic text-center py-2">
          No fields configured. Edit the experiment's Record Template to add fields.
        </p>
      )}

      <div className="flex items-center justify-between pt-2 border-t border-gray-100">
        <div>
          {existing && onRequestDelete && (
            <Button variant="danger" type="button" onClick={onRequestDelete} disabled={loading}>Delete entry</Button>
          )}
        </div>
        <div className="flex items-center gap-3">
          {existing && onNavigate && (
            <div className="flex gap-1">
              <button type="button" onClick={() => handleNavigate('prev')} disabled={loading || !hasPrev}
                title="Save & go to previous entry"
                className="px-2 py-1 rounded border border-gray-300 text-gray-500 text-sm hover:bg-gray-50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors">
                ←
              </button>
              <button type="button" onClick={() => handleNavigate('next')} disabled={loading || !hasNext}
                title="Save & go to next entry"
                className="px-2 py-1 rounded border border-gray-300 text-gray-500 text-sm hover:bg-gray-50 disabled:opacity-30 disabled:cursor-not-allowed transition-colors">
                →
              </button>
            </div>
          )}
          <Button variant="secondary" type="button" onClick={onCancel} disabled={loading}>Cancel</Button>
          <Button type="submit" loading={loading}>{existing ? 'Save Changes' : 'Log Status'}</Button>
        </div>
      </div>
    </form>
  );
}
