// ─────────────────────────────────────────────
// DO_ListView.jsx  (V7)
//
// V7 changes vs V6:
//   - Receives layoutData prop (not allObjects)
//   - listview config: field_code not field
//   - display: 'list' | 'card' mode
//   - tableRow: { tCode, tNum, name, ... }
//   - No getListViewConfig() — config in layoutData
//   - Records endpoint unchanged (/v6/records)
// ─────────────────────────────────────────────

const DOListView = React.forwardRef(function DOListView({
  tableRow,
  layoutData,
  searchOpen,
  onSearchClose,
  onOpen,
  onFoundSetChange,
  onTotalRecords,
  theme = {},
}, ref) {

  const tCode = tableRow?.tCode || tableRow?.code || '';
  const cfg   = layoutData?.listview || null;

  // Derive config from listview JSON (V7) or fallback defaults
  const fields   = cfg?.fields?.length
    ? cfg.fields.map(f => ({ ...f, field: f.field_code || f.field }))
    : (layoutData?.schema?.fields || [])
        .filter(f => f.status !== 0)
        .slice(0, 5)
        .map(f => ({ field: f.code, label: f.name, width: 2 }));

  const pageSize = parseInt(cfg?.pagesize) || 25;
  const defSort  = cfg?.sortfield || 'r_auto';
  const defDir   = cfg?.sortdir   || 'asc';
  const display  = cfg?.display   || 'list';
  const editable = cfg?.editable  || false;
  const label    = tableRow?.name || tCode;

  // Resolve colors — listview JSON overrides app theme
  const headerBg    = cfg?.nav_bg    || theme?.nav_bg    || '#0f2744';
  const headerColor = cfg?.nav_color || theme?.nav_color || '#ffffff';
  const cardBg      = theme?.card_bg || '#ffffff';
  const cardRadius  = theme?.border_radius ? `${theme.border_radius}px` : '8px';

  const foundSetRef = React.useRef([]);

  React.useImperativeHandle(ref, () => ({
    refresh: () => fetchPage(offset, sort, dir, activeSearch),
    goNext:  () => goToPage(currentPage + 1),
    goPrev:  () => goToPage(currentPage - 1),
  }));

  const [records,      setRecords]      = React.useState([]);
  const [total,        setTotal]        = React.useState(0);
  const [offset,       setOffset]       = React.useState(0);
  const [sort,         setSort]         = React.useState(defSort);
  const [dir,          setDir]          = React.useState(defDir);
  const [loading,      setLoading]      = React.useState(true);
  const [error,        setError]        = React.useState(null);

  // Search state
  const [searchGlobal, setSearchGlobal] = React.useState('');
  const [searchField,  setSearchField]  = React.useState('');
  const [searchOp,     setSearchOp]     = React.useState('contains');
  const [searchValue,  setSearchValue]  = React.useState('');
  const [activeSearch, setActiveSearch] = React.useState(null);

  const fieldList   = fields.map(f => f.field).join(',');
  const currentPage = Math.floor(offset / pageSize);
  const totalPages  = Math.ceil(total / pageSize);

  // ── Fetch page ────────────────────────────────
  const fetchPage = React.useCallback(async (newOffset, newSort, newDir, search) => {
    setLoading(true);
    setError(null);

    const params = new URLSearchParams({
      app: APP_ID, table: tCode,
      fields: fieldList,
      limit: pageSize, offset: newOffset,
      sort: newSort, dir: newDir,
    });
    if (search?.type === 'global') {
      params.set('search', search.term);
      params.set('searchfields', fieldList);
    }
    if (search?.type === 'field') {
      params.set('field', search.field);
      params.set('op',    search.op);
      params.set('value', search.value);
    }

    try {
      const res  = await apiFetch(`${API_BASE}/v6/records?${params}&_t=${Date.now()}`);
      const data = await res.json();
      if (data.status !== 'ok') throw new Error(data.message);

      setRecords(data.records);
      setTotal(data.total);
      setOffset(newOffset);
      setSort(newSort);
      setDir(newDir);
      onTotalRecords && onTotalRecords(data.total);
      fetchFoundSet(newSort, newDir, search, data.total);
    } catch(err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }, [tCode, fieldList, pageSize]);

  // ── Fetch full found set ──────────────────────
  const fetchFoundSet = React.useCallback(async (newSort, newDir, search, total) => {
    if (!total) { onFoundSetChange && onFoundSetChange([], 0, pageSize, 0); return; }
    const params = new URLSearchParams({
      app: APP_ID, table: tCode,
      fields: 'r_auto',
      limit: Math.min(total, 5000), offset: 0,
      sort: newSort, dir: newDir,
    });
    if (search?.type === 'global') {
      params.set('search', search.term);
      params.set('searchfields', fieldList);
    }
    if (search?.type === 'field') {
      params.set('field', search.field);
      params.set('op',    search.op);
      params.set('value', search.value);
    }
    try {
      const res  = await apiFetch(`${API_BASE}/v6/records?${params}`);
      const data = await res.json();
      if (data.status !== 'ok') return;
      const ids = data.records.map(r => r.r_auto);
      foundSetRef.current = ids;
      onFoundSetChange && onFoundSetChange(ids, data.total, pageSize, 0);
    } catch(e) {}
  }, [tCode, fieldList, pageSize]);

  // ── Initial load ──────────────────────────────
  React.useEffect(() => {
    setActiveSearch(null);
    setRecords([]); setTotal(0); setOffset(0);
    setSort(defSort); setDir(defDir);
    fetchPage(0, defSort, defDir, null);
  }, [tCode]);

  // ── Sort toggle ───────────────────────────────
  const handleSort = (field) => {
    const newDir = sort === field && dir === 'asc' ? 'desc' : 'asc';
    setSort(field); setDir(newDir);
    fetchPage(0, field, newDir, activeSearch);
  };

  // ── Pagination ────────────────────────────────
  const goToPage = (page) => {
    const newOffset = Math.max(0, Math.min(page, totalPages - 1)) * pageSize;
    fetchPage(newOffset, sort, dir, activeSearch);
  };

  // ── Search ────────────────────────────────────
  const handleSearch = () => {
    let search = null;
    if (searchGlobal.trim()) {
      search = { type:'global', term: searchGlobal.trim() };
    } else if (searchField && searchValue.trim()) {
      search = { type:'field', field: searchField, op: searchOp, value: searchValue.trim() };
    }
    setActiveSearch(search);
    fetchPage(0, sort, dir, search);
    onSearchClose && onSearchClose();
  };

  const handleClearSearch = () => {
    setActiveSearch(null);
    setSearchGlobal(''); setSearchField(''); setSearchValue('');
    fetchPage(0, sort, dir, null);
  };

  const schemaFields = layoutData?.schema?.fields?.filter(f => f.status !== 0) || [];

  // ── Render ────────────────────────────────────
  return (
    <div>

      {/* ── Search panel ── */}
      {searchOpen && (
        <div style={SLV.searchPanel}>
          <div style={{ display:'flex', gap:12, flexWrap:'wrap', alignItems:'flex-end' }}>
            <div>
              <div style={SLV.searchLabel}>Search All Fields</div>
              <input value={searchGlobal}
                onChange={e => setSearchGlobal(e.target.value)}
                onKeyDown={e => e.key === 'Enter' && handleSearch()}
                placeholder={`Search ${label}…`}
                style={SLV.searchInput} />
            </div>
            <div style={SLV.searchOr}>— or —</div>
            <div>
              <div style={SLV.searchLabel}>Field</div>
              <select value={searchField} onChange={e => setSearchField(e.target.value)}
                style={SLV.searchSelect}>
                <option value="">Select field…</option>
                {schemaFields.map(f => (
                  <option key={f.id} value={f.code}>{f.name}</option>
                ))}
              </select>
            </div>
            <div>
              <div style={SLV.searchLabel}>Condition</div>
              <select value={searchOp} onChange={e => setSearchOp(e.target.value)}
                style={SLV.searchSelect}>
                <option value="contains">Contains</option>
                <option value="equals">Equals</option>
                <option value="starts">Starts with</option>
                <option value="ends">Ends with</option>
                <option value="empty">Is empty</option>
                <option value="notempty">Is not empty</option>
              </select>
            </div>
            <div>
              <div style={SLV.searchLabel}>Value</div>
              <input value={searchValue}
                onChange={e => setSearchValue(e.target.value)}
                onKeyDown={e => e.key === 'Enter' && handleSearch()}
                placeholder="Search value…"
                style={SLV.searchInput} />
            </div>
            <div style={{ display:'flex', gap:8 }}>
              <button onClick={handleSearch} style={SLV.searchBtn}>Search</button>
              {activeSearch && (
                <button onClick={handleClearSearch} style={SLV.clearBtn}>Clear</button>
              )}
              <button onClick={onSearchClose} style={SLV.closeBtn}>✕</button>
            </div>
          </div>
          {activeSearch && (
            <div style={SLV.activeSearch}>
              🔍 Active search
              <button onClick={handleClearSearch} style={SLV.clearSearchLink}>Clear</button>
            </div>
          )}
        </div>
      )}

      {error && (
        <div style={{ background:'#fef2f2', color:'#991b1b', padding:'10px 14px',
                      borderRadius:6, marginBottom:12, fontSize:13 }}>
          ❌ {error}
        </div>
      )}

      {/* ── LIST display ── */}
      {display === 'list' && (
        <div style={{ background:cardBg, borderRadius:cardRadius,
                      boxShadow:'0 1px 4px rgba(0,0,0,0.06)', overflow:'hidden' }}>
          <table style={SLV.table}>
            <thead>
              <tr>
                {fields.map(f => (
                  <th key={f.field}
                    onClick={() => handleSort(f.field)}
                    style={{ ...SLV.th, width:`${(f.width||2) * 8}%`,
                             background: headerBg, color: headerColor }}>
                    {f.label || f.field}
                    {sort === f.field && (
                      <span style={{ marginLeft:4, opacity:0.8 }}>
                        {dir === 'asc' ? '↑' : '↓'}
                      </span>
                    )}
                  </th>
                ))}
                <th style={{ ...SLV.th, width:24,
                             background: headerBg, color: headerColor }}></th>
              </tr>
            </thead>
            <tbody>
              {loading && (
                <tr>
                  <td colSpan={fields.length + 1}
                    style={{ padding:'20px', textAlign:'center', color:'#94a3b8', fontSize:13 }}>
                    Loading…
                  </td>
                </tr>
              )}
              {!loading && records.length === 0 && (
                <tr>
                  <td colSpan={fields.length + 1}
                    style={{ padding:'20px', textAlign:'center', color:'#94a3b8', fontSize:13 }}>
                    No records found
                  </td>
                </tr>
              )}
              {!loading && records.map((row, ri) => (
                <tr key={row.r_auto}
                  onClick={() => onOpen && onOpen(row.r_auto, foundSetRef.current, total)}
                  style={SLV.tr}
                  onMouseEnter={e => e.currentTarget.style.background = '#f8fafc'}
                  onMouseLeave={e => e.currentTarget.style.background = ''}>
                  {fields.map(f => (
                    <td key={f.field} style={SLV.td}>
                      {row[f.field] || <span style={{ color:'#cbd5e1' }}>—</span>}
                    </td>
                  ))}
                  <td style={{ ...SLV.td, color:'#2563eb', textAlign:'right',
                                paddingRight:12 }}>▶</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* ── CARD display ── */}
      {display === 'card' && (
        <div style={{ background:cardBg, borderRadius:cardRadius,
                      boxShadow:'0 1px 4px rgba(0,0,0,0.06)',
                      padding:'16px' }}>
          <div style={SLV.cardGrid}>
          {loading && (
            <div style={{ gridColumn:'1/-1', padding:'20px', textAlign:'center',
                          color:'#94a3b8', fontSize:13 }}>Loading…</div>
          )}
          {!loading && records.length === 0 && (
            <div style={{ gridColumn:'1/-1', padding:'20px', textAlign:'center',
                          color:'#94a3b8', fontSize:13 }}>No records found</div>
          )}
          {!loading && records.map(row => (
            <div key={row.r_auto}
              onClick={() => onOpen && onOpen(row.r_auto, foundSetRef.current, total)}
              style={SLV.card}
              onMouseEnter={e => { e.currentTarget.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)'; e.currentTarget.style.borderColor = '#2563eb'; }}
              onMouseLeave={e => { e.currentTarget.style.boxShadow = SLV.card.boxShadow; e.currentTarget.style.borderColor = '#e2e8f0'; }}>
              {fields.map((f, fi) => (
                <div key={f.field} style={{ marginBottom: fi < fields.length-1 ? 6 : 0 }}>
                  {fi === 0
                    ? <div style={{ fontSize:15, fontWeight:700, color:'#0f1923' }}>
                        {row[f.field] || '—'}
                      </div>
                    : <div style={{ fontSize:12, color:'#64748b' }}>
                        <span style={{ fontWeight:500, color:'#94a3b8', marginRight:4 }}>
                          {f.label}:
                        </span>
                        {row[f.field] || '—'}
                      </div>
                  }
                </div>
              ))}
            </div>
          ))}
        </div>
        </div>
      )}

      {/* ── Pagination ── */}
      {total > pageSize && (
        <div style={SLV.pagination}>
          <button onClick={() => goToPage(0)}
            disabled={offset === 0} style={SLV.pageBtn}>«</button>
          <button onClick={() => goToPage(currentPage - 1)}
            disabled={offset === 0} style={SLV.pageBtn}>‹</button>
          <span style={{ fontSize:12, color:'#64748b', padding:'0 8px' }}>
            {offset + 1}–{Math.min(offset + pageSize, total)} of {total}
          </span>
          <button onClick={() => goToPage(currentPage + 1)}
            disabled={offset + pageSize >= total} style={SLV.pageBtn}>›</button>
          <button onClick={() => goToPage(totalPages - 1)}
            disabled={offset + pageSize >= total} style={SLV.pageBtn}>»</button>
        </div>
      )}
    </div>
  );
});

// ─────────────────────────────────────────────
// Styles — prefix SLV
// ─────────────────────────────────────────────
const SLV = {
  tableWrap:    { border:'1px solid #e2e8f0', borderRadius:8, overflow:'hidden' },
  table:        { width:'100%', borderCollapse:'collapse', fontSize:13 },
  th:           { padding:'10px 12px', background:'#f8fafc', textAlign:'left',
                  borderBottom:'2px solid #e2e8f0', fontSize:12, fontWeight:700,
                  color:'#64748b', cursor:'pointer', userSelect:'none',
                  letterSpacing:'0.03em', textTransform:'uppercase' },
  tr:           { cursor:'pointer', transition:'background 0.1s', borderBottom:'1px solid #f1f5f9' },
  td:           { padding:'10px 12px', color:'#0f1923', fontSize:13 },
  cardGrid:     { display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(240px, 1fr))',
                  gap:12 },
  card:         { background:'#fff', border:'1.5px solid #e2e8f0', borderRadius:10,
                  padding:'16px', cursor:'pointer',
                  boxShadow:'0 1px 3px rgba(0,0,0,0.05)',
                  transition:'box-shadow 0.15s, border-color 0.15s' },
  pagination:   { display:'flex', alignItems:'center', justifyContent:'center',
                  gap:4, marginTop:16, padding:'8px 0' },
  pageBtn:      { padding:'5px 10px', border:'1.5px solid #e2e8f0', borderRadius:6,
                  background:'#fff', cursor:'pointer', fontSize:13, color:'#374151',
                  fontFamily:'DM Sans, sans-serif' },
  searchPanel:  { background:'#f8fafc', border:'1px solid #e2e8f0', borderRadius:8,
                  padding:'14px 16px', marginBottom:16 },
  searchLabel:  { fontSize:10, fontWeight:700, color:'#94a3b8', textTransform:'uppercase',
                  letterSpacing:'0.06em', marginBottom:4 },
  searchInput:  { padding:'7px 10px', border:'1.5px solid #e2e8f0', borderRadius:6,
                  fontSize:13, fontFamily:'DM Sans, sans-serif', outline:'none',
                  minWidth:200 },
  searchSelect: { padding:'7px 10px', border:'1.5px solid #e2e8f0', borderRadius:6,
                  fontSize:13, fontFamily:'DM Sans, sans-serif', background:'#fff',
                  outline:'none' },
  searchOr:     { fontSize:11, color:'#94a3b8', paddingBottom:4 },
  searchBtn:    { padding:'7px 16px', background:'#0f1923', color:'#fff', border:'none',
                  borderRadius:6, fontSize:13, fontWeight:600, cursor:'pointer',
                  fontFamily:'DM Sans, sans-serif' },
  clearBtn:     { padding:'7px 12px', background:'#fff', color:'#374151',
                  border:'1.5px solid #e2e8f0', borderRadius:6, fontSize:13,
                  cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  closeBtn:     { padding:'7px 10px', background:'#fff', color:'#94a3b8',
                  border:'1.5px solid #e2e8f0', borderRadius:6, fontSize:13,
                  cursor:'pointer', fontFamily:'DM Sans, sans-serif' },
  activeSearch: { marginTop:10, fontSize:12, color:'#2563eb',
                  display:'flex', alignItems:'center', gap:8 },
  clearSearchLink: { background:'none', border:'none', color:'#dc2626',
                     cursor:'pointer', fontSize:12, fontFamily:'DM Sans, sans-serif' },
};
