import React, { useEffect, useRef, useState, useCallback } from 'react';
import { useParams, useNavigate, Link, useLocation } from 'react-router-dom';
import { animalsApi, dailyStatusesApi, experimentsApi } from '../api/client';
import { format } from 'date-fns';
import Button from '../components/ui/Button';
import Modal from '../components/ui/Modal';
import ConfirmDialog from '../components/ui/ConfirmDialog';
import DailyStatusForm from '../components/DailyStatusForm';
import SubjectInfoForm from '../components/SubjectInfoForm';
import Alert from '../components/ui/Alert';
import AuditLogSection from '../components/AuditLogSection';
import { SubjectAnalysisCharts } from '../components/AnalysisCharts';

/** Read the value for a template field from a status record.
 *  Custom fields are keyed by fieldId, not by the display key. */
function getFieldValue(status, field) {
  if (field.builtin) return status[field.key];
  return status.custom_fields?.[field.fieldId];
}

// ── Inline cell editor ─────────────────────────────────────────────────────────

function InlineCell({ statusId, field, value, currentStatus, onSaved }) {
  const [editing, setEditing]     = useState(false);
  const [draft, setDraft]         = useState('');
  const [saving, setSaving]       = useState(false);
  const [saveError, setSaveError] = useState(null);
  const inputRef = useRef(null);
  const isTextarea = field.type === 'textarea';

  function startEdit(e) {
    e.preventDefault();
    e.stopPropagation();
    setDraft(value ?? '');
    setSaveError(null);
    setEditing(true);
  }

  useEffect(() => {
    if (editing && inputRef.current) {
      inputRef.current.focus();
      if (inputRef.current.select) inputRef.current.select();
    }
  }, [editing]);

  async function commit() {
    setEditing(false);
    const newValue = draft.trim() || null;
    if (newValue === (value?.trim() || null)) return;
    setSaving(true);
    setSaveError(null);
    try {
      let body;
      if (field.builtin) {
        body = { [field.key]: newValue };
      } else {
        body = { custom_fields: { ...currentStatus.custom_fields, [field.fieldId]: newValue } };
      }
      const updated = await dailyStatusesApi.update(statusId, body);
      onSaved(updated);
    } catch (err) {
      setSaveError(err.message ?? 'Save failed');
    } finally {
      setSaving(false);
    }
  }

  function cancel() { setEditing(false); }

  if (editing) {
    const sharedProps = {
      ref: inputRef,
      value: draft,
      onChange: (e) => setDraft(e.target.value),
      onBlur: commit,
      onClick: (e) => e.stopPropagation(),
      onKeyDown: (e) => {
        if (e.key === 'Escape') { e.preventDefault(); cancel(); }
        if (e.key === 'Enter' && !isTextarea) { e.preventDefault(); commit(); }
      },
      className: 'w-full border border-indigo-400 rounded px-1.5 py-0.5 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 bg-white',
    };
    return isTextarea
      ? <textarea {...sharedProps} rows={3} className={sharedProps.className + ' resize-none'} />
      : <input type="text" {...sharedProps} />;
  }

  return (
    <div
      onDoubleClick={startEdit}
      title={editing ? '' : 'Double-click to edit'}
      className={`min-h-[1.25rem] cursor-default rounded transition-colors px-0.5 -mx-0.5
        ${saving ? 'opacity-40' : 'hover:bg-indigo-50/60 group/ic'}`}
    >
      {saveError
        ? <span className="text-red-500 text-xs">{saveError}</span>
        : value
          ? isTextarea
            ? <span className="line-clamp-2 whitespace-pre-wrap">{value}</span>
            : <span className="truncate block">{value}</span>
          : <span className="text-gray-200 group-hover/ic:text-gray-400 select-none text-xs">· · ·</span>
      }
    </div>
  );
}

export default function AnimalDetail() {
  const { id } = useParams();
  const navigate = useNavigate();
  const location = useLocation();

  const [animal, setAnimal] = useState(null);
  const [statuses, setStatuses] = useState([]);
  const [template, setTemplate] = useState([]);
  const [subjectTemplate, setSubjectTemplate] = useState([]);
  const [showSubjectInfo, setShowSubjectInfo] = useState(false);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [successMsg, setSuccessMsg] = useState(null);

  const [showAddStatus, setShowAddStatus] = useState(false);
  const [editStatus, setEditStatus] = useState(null);
  const [deleteStatus, setDeleteStatus] = useState(null);
  const [deleteLoading, setDeleteLoading] = useState(false);
  const [showDeleteSubject, setShowDeleteSubject] = useState(false);
  const [deleteSubjectLoading, setDeleteSubjectLoading] = useState(false);
  const [fillingGaps, setFillingGaps] = useState(false);

  // Column visibility — persisted per experiment
  const [hiddenCols, setHiddenCols] = useState(new Set());
  const [showColPicker, setShowColPicker] = useState(false);
  const colPickerRef = useRef(null);

  useEffect(() => {
    if (!animal) return;
    const stored = localStorage.getItem(`col-vis-${animal.id}`);
    setHiddenCols(stored ? new Set(JSON.parse(stored)) : new Set());
  }, [animal?.id]);

  function toggleCol(fieldId) {
    setHiddenCols((prev) => {
      const next = new Set(prev);
      next.has(fieldId) ? next.delete(fieldId) : next.add(fieldId);
      localStorage.setItem(`col-vis-${animal.id}`, JSON.stringify([...next]));
      return next;
    });
  }

  useEffect(() => {
    if (!showColPicker) return;
    function handleClick(e) {
      if (colPickerRef.current && !colPickerRef.current.contains(e.target)) {
        setShowColPicker(false);
      }
    }
    document.addEventListener('mousedown', handleClick);
    return () => document.removeEventListener('mousedown', handleClick);
  }, [showColPicker]);

  async function load() {
    setLoading(true);
    setError(null);
    try {
      const [animalData, statusData] = await Promise.all([
        animalsApi.get(id),
        dailyStatusesApi.list(id),
      ]);
      setAnimal(animalData);
      setStatuses(statusData);

      const [tmpl, subjTmpl] = await Promise.all([
        experimentsApi.getTemplate(animalData.experiment_id),
        experimentsApi.getSubjectTemplate(animalData.experiment_id),
      ]);
      setTemplate(tmpl);
      setSubjectTemplate(subjTmpl);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => { load(); }, [id]);

  function flash(msg) {
    setSuccessMsg(msg);
    setTimeout(() => setSuccessMsg(null), 3000);
  }

  function handleStatusSaved() {
    setShowAddStatus(false);
    setEditStatus(null);
    load();
    flash(editStatus ? 'Daily status updated.' : 'Daily status logged.');
  }

  async function handleDeleteStatus() {
    setDeleteLoading(true);
    try {
      await dailyStatusesApi.delete(deleteStatus.id);
      setDeleteStatus(null);
      setEditStatus(null);
      load();
      flash('Daily status removed.');
    } catch (err) {
      setError(err.message);
      setDeleteStatus(null);
    } finally {
      setDeleteLoading(false);
    }
  }

  async function fillGaps() {
    setFillingGaps(true);
    try {
      await Promise.all(missingDates.map((date) => dailyStatusesApi.create({ date, animal_id: id })));
      load();
      flash(`Created ${missingDates.length} missing entr${missingDates.length === 1 ? 'y' : 'ies'}.`);
    } catch (err) {
      setError(err.message);
    } finally {
      setFillingGaps(false);
    }
  }

  async function handleDeleteSubject() {
    setDeleteSubjectLoading(true);
    try {
      await animalsApi.delete(animal.id);
      navigate(`/experiments/${animal.experiment_id}`, { replace: true });
    } catch (err) {
      setError(err.message);
      setShowDeleteSubject(false);
    } finally {
      setDeleteSubjectLoading(false);
    }
  }

  if (loading) return <div className="max-w-5xl mx-auto px-4 py-8 text-gray-400" aria-live="polite" aria-busy="true">Loading…</div>;
  if (error) return (
    <div className="max-w-5xl mx-auto px-4 py-8">
      <Alert type="error" message={error} />
      <Button variant="secondary" className="mt-4" onClick={() => navigate(-1)}>← Back</Button>
    </div>
  );

  const activeFields = template.filter((f) => f.active);
  const visibleFields = activeFields.filter((f) => !hiddenCols.has(f.fieldId));

  // Dates with entries
  const existingDateSet = new Set(statuses.map((s) => String(s.date).slice(0, 10)));
  const missingDates = (() => {
    if (statuses.length < 2) return [];
    const sorted = [...existingDateSet].sort();
    const missing = [];
    const cur = new Date(sorted[0] + 'T12:00:00');
    const end = new Date(sorted[sorted.length - 1] + 'T12:00:00');
    while (cur < end) {
      cur.setDate(cur.getDate() + 1);
      const d = cur.toISOString().slice(0, 10);
      if (!existingDateSet.has(d)) missing.push(d);
    }
    return missing;
  })();

  return (
    <div className="max-w-5xl mx-auto px-4 py-8">
      {/* Breadcrumb */}
      <nav className="text-sm text-gray-500 mb-4">
        <Link to="/" className="hover:text-blue-600">Experiments</Link>
        <span className="mx-2">/</span>
        <Link to={`/experiments/${animal.experiment_id}`} className="hover:text-blue-600">Experiment</Link>
        <span className="mx-2">/</span>
        <span className="text-gray-900 font-medium">{animal.animal_name}</span>
      </nav>

      <div className="flex items-start justify-between mb-6">
        <div>
          <h1 className="text-2xl font-bold text-gray-900">{animal.animal_name}</h1>
          <p className="text-sm text-gray-500 mt-0.5">
            ID: <span className="font-mono">{animal.animal_id_string}</span>
            {' · '}
            {statuses.length} daily status {statuses.length !== 1 ? 'entries' : 'entry'}
          </p>
        </div>
        <Button onClick={() => setShowAddStatus(true)}>+ Log Daily Status</Button>
      </div>

      {successMsg && <Alert type="success" message={successMsg} />}
      {error && <Alert type="error" message={error} onDismiss={() => setError(null)} />}

      {/* Subject information card */}
      {subjectTemplate.filter((f) => f.active).length > 0 && (
        <div className="bg-white border border-gray-200 rounded-xl p-5 mb-6">
          <div className="flex items-center justify-between mb-3">
            <h2 className="text-sm font-semibold text-gray-700 uppercase tracking-wide">Subject Information</h2>
            <button
              type="button"
              onClick={() => setShowSubjectInfo(true)}
              className="text-xs text-gray-400 hover:text-blue-600 transition-colors inline-flex items-center gap-1"
            >
              <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15.232 5.232l3.536 3.536M9 13l6.586-6.586a2 2 0 112.828 2.828L11.828 15.828A2 2 0 0110 16.414V19h2.586a2 2 0 001.414-.586l6.5-6.5" />
              </svg>
              Edit
            </button>
          </div>
          {(() => {
            const filled = subjectTemplate.filter((f) => f.active && animal.subject_info?.[f.fieldId]);
            if (filled.length === 0) {
              return (
                <button
                  type="button"
                  onClick={() => setShowSubjectInfo(true)}
                  className="text-sm text-gray-400 italic hover:text-blue-600 transition-colors"
                >
                  No information recorded yet — click to add
                </button>
              );
            }
            return (
              <dl className="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-2 text-sm">
                {filled.map((f) => (
                  <div key={f.fieldId} className={f.type === 'textarea' ? 'sm:col-span-2' : ''}>
                    <dt className="text-xs font-medium text-gray-500 uppercase tracking-wide">{f.label}</dt>
                    <dd className="text-gray-800 mt-0.5 whitespace-pre-wrap">{animal.subject_info[f.fieldId]}</dd>
                  </div>
                ))}
              </dl>
            );
          })()}
        </div>
      )}

      {statuses.length === 0 ? (
        <div className="text-center py-16 border-2 border-dashed border-gray-200 rounded-xl">
          <p className="text-gray-400 mb-3">No daily statuses logged yet.</p>
          <Button onClick={() => setShowAddStatus(true)}>+ Log First Status</Button>
        </div>
      ) : (
        <div className="border border-gray-200 rounded-xl overflow-hidden">
          {/* Column picker toolbar */}
          {activeFields.length > 0 && (
            <div className="flex justify-end px-3 py-1.5 border-b border-gray-100 bg-gray-50/60">
              <div className="relative" ref={colPickerRef}>
                <button
                  type="button"
                  onClick={() => setShowColPicker((v) => !v)}
                  className="inline-flex items-center gap-1 text-xs text-gray-500 hover:text-gray-800 px-2 py-1 rounded hover:bg-gray-100 transition-colors"
                >
                  <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
                  </svg>
                  Columns
                  {hiddenCols.size > 0 && (
                    <span className="ml-0.5 bg-indigo-100 text-indigo-700 rounded-full px-1.5 py-px text-[10px] font-medium leading-none">
                      {activeFields.length - hiddenCols.size}/{activeFields.length}
                    </span>
                  )}
                </button>
                {showColPicker && (
                  <div className="absolute right-0 top-full mt-1 z-30 bg-white border border-gray-200 rounded-lg shadow-lg p-2 min-w-[180px]">
                    <p className="text-[10px] font-semibold text-gray-400 uppercase tracking-wide px-1 mb-1">Show / hide columns</p>
                    {activeFields.map((f) => {
                      const visible = !hiddenCols.has(f.fieldId);
                      return (
                        <label key={f.fieldId} className="flex items-center gap-2 px-1 py-0.5 rounded hover:bg-gray-50 cursor-pointer select-none text-xs text-gray-700">
                          <input
                            type="checkbox"
                            checked={visible}
                            onChange={() => toggleCol(f.fieldId)}
                            className="w-3.5 h-3.5 accent-indigo-600"
                          />
                          <span className="truncate" title={f.label}>{f.label}</span>
                        </label>
                      );
                    })}
                    {hiddenCols.size > 0 && (
                      <button
                        type="button"
                        onClick={() => {
                          setHiddenCols(new Set());
                          localStorage.removeItem(`col-vis-${animal.id}`);
                        }}
                        className="mt-1 w-full text-left text-[10px] text-indigo-500 hover:text-indigo-700 px-1 py-0.5"
                      >
                        Show all
                      </button>
                    )}
                  </div>
                )}
              </div>
            </div>
          )}

          <div className="overflow-x-auto">
            <table className="text-sm border-collapse min-w-full">
              <thead>
                <tr className="bg-gray-50 border-b border-gray-200">
                  <th className="text-left px-3 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wide whitespace-nowrap sticky left-0 bg-gray-50 z-10 border-r border-gray-200 min-w-[110px]">
                    Date
                  </th>
                  {visibleFields.map((f) => {
                    const header = f.abbr ? (f.unit ? `${f.abbr} (${f.unit})` : f.abbr) : (f.unit ? `${f.label} (${f.unit})` : f.label);
                    const tooltip = f.unit ? `${f.label} (${f.unit})` : f.label;
                    const minW = Math.max(80, header.length * 7.5 + 24);
                    return (
                      <th key={f.key} title={tooltip} style={{ minWidth: minW }} className="text-left px-3 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wide whitespace-nowrap max-w-[220px] cursor-default">
                        {header}
                      </th>
                    );
                  })}
                  {activeFields.length === 0 && (
                    <>
                      {['Experiment Description', 'Vitals', 'Treatment', 'Notes'].map((l) => (
                        <th key={l} className="text-left px-3 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wide whitespace-nowrap min-w-[120px]">{l}</th>
                      ))}
                    </>
                  )}
                  <th className="sticky right-0 bg-gray-50 z-10 border-l border-gray-200 px-3 py-2 min-w-[96px]" />
                </tr>
              </thead>
              <tbody>
                {statuses.map((s, i) => {
                  const rowBg = i % 2 === 0 ? 'bg-white' : 'bg-gray-50/40';
                  const renderFields = activeFields.length > 0 ? visibleFields : [
                    { fieldId: '__exp_desc__', key: 'experiment_description', label: 'Experiment Description', type: 'textarea', builtin: true, active: true },
                    { fieldId: '__vitals__',   key: 'vitals',                 label: 'Vitals',                 type: 'text',     builtin: true, active: true },
                    { fieldId: '__treatment__',key: 'treatment',              label: 'Treatment',              type: 'text',     builtin: true, active: true },
                    { fieldId: '__notes__',    key: 'notes',                  label: 'Notes',                  type: 'textarea', builtin: true, active: true },
                  ];
                  return (
                    <tr key={s.id} className={`border-b border-gray-100 last:border-0 ${rowBg}`}>
                      <td
                        className={`px-3 py-2 font-medium text-gray-700 whitespace-nowrap sticky left-0 z-10 border-r border-gray-100 cursor-pointer hover:text-blue-600 hover:bg-blue-50/40 transition-colors ${rowBg}`}
                        onClick={() => navigate(`/daily-statuses/${s.id}`)}
                      >
                        {format(new Date(String(s.date).slice(0, 10) + 'T12:00:00'), 'MMM d, yyyy')}
                      </td>
                      {renderFields.map((f) => (
                        <td key={f.fieldId} className="px-3 py-1.5 text-gray-700 max-w-[220px]">
                          <InlineCell
                            statusId={s.id}
                            field={f}
                            value={getFieldValue(s, f)}
                            currentStatus={s}
                            onSaved={(updated) => setStatuses((prev) => prev.map((x) => x.id === s.id ? { ...x, ...updated } : x))}
                          />
                        </td>
                      ))}
                      <td className={`px-2 py-1.5 sticky right-0 z-10 border-l border-gray-100 ${rowBg}`}>
                        <div className="flex gap-1 justify-end">
                          <Button size="sm" variant="secondary" onClick={() => setEditStatus(s)}>Edit</Button>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {missingDates.length > 0 && (
        <div className="mt-3 flex items-center justify-between px-4 py-3 bg-amber-50 border border-amber-200 rounded-xl">
          <p className="text-sm text-amber-800">
            <span className="font-semibold">{missingDates.length}</span> date{missingDates.length !== 1 ? 's' : ''} between the earliest and latest entries have no record.
          </p>
          <Button variant="secondary" size="sm" onClick={fillGaps} loading={fillingGaps}>
            Create {missingDates.length} empty entr{missingDates.length === 1 ? 'y' : 'ies'}
          </Button>
        </div>
      )}

      <SubjectAnalysisCharts statuses={statuses} dailyTemplate={template} />

      <AuditLogSection tableName="daily_statuses" limit={5} />

      {/* Danger zone */}
      <div className="mt-10 border border-red-200 rounded-xl p-4 bg-red-50/40">
        <h2 className="text-xs font-semibold text-red-600 uppercase tracking-wide mb-2">Danger Zone</h2>
        <div className="flex items-center justify-between">
          <p className="text-sm text-gray-600">Permanently delete this subject and all its daily status records.</p>
          <Button variant="danger" onClick={() => setShowDeleteSubject(true)}>Delete Subject</Button>
        </div>
      </div>

      <Modal isOpen={showSubjectInfo} onClose={() => setShowSubjectInfo(false)} title="Subject Information" size="full">
        <SubjectInfoForm
          animal={animal}
          subjectTemplate={subjectTemplate}
          experimentId={animal?.experiment_id}
          onTemplateUpdate={setSubjectTemplate}
          onSaved={(updated) => { setAnimal(updated); setShowSubjectInfo(false); flash('Subject information saved.'); }}
          onCancel={() => setShowSubjectInfo(false)}
        />
      </Modal>

      <Modal isOpen={showAddStatus} onClose={() => setShowAddStatus(false)} title="Log Daily Status" size="full">
        <DailyStatusForm
          animalId={id}
          experimentId={animal?.experiment_id}
          template={template}
          onTemplateUpdate={setTemplate}
          onSuccess={handleStatusSaved}
          onCancel={() => setShowAddStatus(false)}
        />
      </Modal>

      {(() => {
        const editIdx = editStatus ? statuses.findIndex((s) => s.id === editStatus.id) : -1;
        return (
          <Modal isOpen={!!editStatus} onClose={() => setEditStatus(null)} title="Edit Daily Status" size="full">
            <DailyStatusForm
              existing={editStatus}
              animalId={id}
              experimentId={animal?.experiment_id}
              template={template}
              onTemplateUpdate={setTemplate}
              onSuccess={handleStatusSaved}
              onCancel={() => setEditStatus(null)}
              onRequestDelete={() => setDeleteStatus(editStatus)}
              hasPrev={editIdx > 0}
              hasNext={editIdx < statuses.length - 1}
              onNavigate={(direction, savedResult) => {
                setStatuses((prev) => prev.map((s) => s.id === savedResult.id ? savedResult : s));
                setEditStatus(statuses[direction === 'prev' ? editIdx - 1 : editIdx + 1]);
              }}
            />
          </Modal>
        );
      })()}

      <ConfirmDialog
        isOpen={!!deleteStatus}
        onClose={() => setDeleteStatus(null)}
        onConfirm={handleDeleteStatus}
        loading={deleteLoading}
        title="Delete Daily Status"
        message={`Delete the status entry for ${deleteStatus ? format(new Date(String(deleteStatus.date).slice(0, 10) + 'T12:00:00'), 'MMMM d, yyyy') : ''}? This cannot be undone.`}
        confirmWord="delete"
      />

      <ConfirmDialog
        isOpen={showDeleteSubject}
        onClose={() => setShowDeleteSubject(false)}
        onConfirm={handleDeleteSubject}
        loading={deleteSubjectLoading}
        title="Delete Subject"
        message={`This will permanently delete "${animal.animal_name}" and all ${statuses.length} daily status record${statuses.length !== 1 ? 's' : ''}. This cannot be undone.`}
        confirmWord="delete"
      />
    </div>
  );
}
