// ─── 필지 목록 뷰 ────────────────────────────
function ParcelListView({
  data,
  overrides,
  groups,
  parcelToGroup,
  colors,
  colorLabels,
  colorById,
  areas,
  areaUnit,
  onAreaUnitChange,
  onBack,
  onSelectParcel,
}) {
  const [searchText, setSearchText] = useState('');
  const [colorFilter, setColorFilter] = useState([]); // [] = 전체
  const [sortBy, setSortBy] = useState('jibun');

  // 필지별 표시 데이터 계산
  const allRows = useMemo(() => {
    return data.parcels.map(p => {
      const groupId = parcelToGroup[p.id];
      const ov = groupId ? groups[groupId] : overrides[p.id];
      const displayName = overrides[p.id]?.name || p.jibun;
      const colorId = ov?.color || null;
      const groupName = groupId ? (groups[groupId]?.name || null) : null;
      const realArea = areas[p.id]?.lndpcl_ar ?? null;
      return { id: p.id, jibun: p.jibun, displayName, colorId, area: p.area, realArea, groupName };
    });
  }, [data.parcels, overrides, groups, parcelToGroup, areas]);

  // 중복 jibun 사전 계산 (2개 이상인 jibun 값 Set)
  const duplicateJibuns = useMemo(() => {
    const counts = {};
    allRows.forEach(r => { counts[r.jibun] = (counts[r.jibun] || 0) + 1; });
    return new Set(Object.keys(counts).filter(j => counts[j] > 1));
  }, [allRows]);

  // 검색 + 색상 필터
  const filtered = useMemo(() => {
    let result = allRows;
    const q = searchText.trim().toLowerCase();
    if (q) {
      result = result.filter(r =>
        r.displayName.toLowerCase().includes(q) ||
        r.jibun.toLowerCase().includes(q) ||
        (r.groupName && r.groupName.toLowerCase().includes(q))
      );
    }
    if (colorFilter.length > 0) {
      result = result.filter(r => {
        if (colorFilter.includes('none') && !r.colorId) return true;
        return r.colorId && colorFilter.includes(r.colorId);
      });
    }
    return result;
  }, [allRows, searchText, colorFilter]);

  // 정렬
  const sorted = useMemo(() => {
    const arr = [...filtered];
    if (sortBy === 'jibun') {
      arr.sort((a, b) => a.jibun.localeCompare(b.jibun, 'ko'));
    } else if (sortBy === 'color') {
      const colorOrder = colors.map(c => c.id);
      const colorRank = (id) => {
        if (!id) return colorOrder.length + 1; // 미지정: 맨 뒤
        const idx = colorOrder.indexOf(id);
        return idx >= 0 ? idx : colorOrder.length; // 삭제된 색상: 미지정 바로 앞
      };
      arr.sort((a, b) => {
        const diff = colorRank(a.colorId) - colorRank(b.colorId);
        if (diff !== 0) return diff;
        return a.jibun.localeCompare(b.jibun, 'ko');
      });
    } else if (sortBy === 'area') {
      // 픽셀 면적(p.area)은 실제 ㎡와 비례 → 상대 정렬 동일
      arr.sort((a, b) => b.area - a.area);
    }
    return arr;
  }, [filtered, sortBy, colors]);

  const toggleColorFilter = (colorId) => {
    setColorFilter(prev =>
      prev.includes(colorId) ? prev.filter(c => c !== colorId) : [...prev, colorId]
    );
  };

  const formatArea = (row) => {
    const m2 = row.realArea;
    if (m2 == null) return '-';
    return convertArea(m2, areaUnit);
  };

  return (
    <div style={appStyles.listView}>
      {/* 헤더: 뒤로가기 + 카운트 */}
      <div style={appStyles.listHeader}>
        <button style={appStyles.listBackBtn} onClick={onBack}>
          <i data-lucide="arrow-left" style={{ width: 16, height: 16 }}></i>
          <span>지도로 돌아가기</span>
        </button>
        <span style={appStyles.listCount}>
          {sorted.length} / {data.parcels.length} 필지
        </span>
      </div>

      {/* 검색창 */}
      <div style={appStyles.listSearchRow}>
        <div style={appStyles.listSearchWrap}>
          <i data-lucide="search" style={{ width: 15, height: 15, color: '#8E8B82', flexShrink: 0 }}></i>
          <input
            type="text"
            placeholder="지번·그룹명 검색…"
            value={searchText}
            onChange={e => setSearchText(e.target.value)}
            style={appStyles.listSearchInput}
          />
          {searchText && (
            <button style={appStyles.listSearchClear} onClick={() => setSearchText('')}>
              <i data-lucide="x" style={{ width: 14, height: 14 }}></i>
            </button>
          )}
        </div>
      </div>

      {/* 색상 필터 칩 */}
      <div style={appStyles.listFilterRow}>
        <button
          style={{ ...appStyles.listChip, ...(colorFilter.length === 0 ? appStyles.listChipActive : {}) }}
          onClick={() => setColorFilter([])}
        >
          전체
        </button>
        {colors.map(c => {
          const isActive = colorFilter.includes(c.id);
          return (
            <button
              key={c.id}
              style={{
                ...appStyles.listChip,
                ...(isActive ? { background: c.hex + '22', border: `1px solid ${c.hex}`, color: c.hex } : {}),
              }}
              onClick={() => toggleColorFilter(c.id)}
            >
              <span style={{ width: 7, height: 7, borderRadius: '50%', background: c.hex, flexShrink: 0, display: 'inline-block' }}></span>
              {c.label}
            </button>
          );
        })}
        <button
          style={{ ...appStyles.listChip, ...(colorFilter.includes('none') ? appStyles.listChipActive : {}) }}
          onClick={() => toggleColorFilter('none')}
        >
          미지정
        </button>
      </div>

      {/* 정렬 + 단위 탭 */}
      <div style={appStyles.listSortRow}>
        <span style={appStyles.listSortLabel}>정렬</span>
        {[
          { id: 'jibun', label: '지번순' },
          { id: 'color', label: '색상순' },
          { id: 'area',  label: '면적순' },
        ].map(s => (
          <button
            key={s.id}
            style={{ ...appStyles.listSortBtn, ...(sortBy === s.id ? appStyles.listSortBtnActive : {}) }}
            onClick={() => setSortBy(s.id)}
          >
            {s.label}
            <i data-lucide="chevron-down" style={{ width: 11, height: 11, marginLeft: 2, opacity: sortBy === s.id ? 1 : 0 }}></i>
          </button>
        ))}
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 2 }}>
          {AREA_UNITS.map(u => (
            <button
              key={u.id}
              style={{ ...appStyles.listSortBtn, ...(areaUnit === u.id ? appStyles.listSortBtnActive : {}) }}
              onClick={() => onAreaUnitChange(u.id)}
            >
              {u.label}
            </button>
          ))}
        </div>
      </div>

      {/* 컬럼 헤더 */}
      <div style={appStyles.listColHeader}>
        <span style={{ flex: '1 1 0', minWidth: 0 }}>지번</span>
        <span style={{ width: 76, flexShrink: 0 }}>색상</span>
        <span style={{ width: 80, flexShrink: 0, textAlign: 'right' }}>면적</span>
        <span style={{ width: 68, flexShrink: 0, paddingLeft: 10 }}>그룹</span>
      </div>

      {/* 목록 */}
      <div style={appStyles.listScroll}>
        {sorted.length === 0 ? (
          <div style={appStyles.listEmpty}>
            <i data-lucide="search-x" style={{ width: 32, height: 32, color: '#C4C0B4' }}></i>
            <span style={{ color: '#8E8B82', fontSize: 13, marginTop: 8 }}>검색 결과 없음</span>
          </div>
        ) : (
          sorted.map((row, idx) => {
            const colorInfo = row.colorId ? colorById[row.colorId] : null;
            const hasCustomName = row.displayName !== row.jibun;
            return (
              <button
                key={row.id}
                style={{ ...appStyles.listRow, ...(idx % 2 === 1 ? { background: '#FAFAF7' } : {}) }}
                onClick={() => onSelectParcel(row.id)}
              >
                {/* 지번 */}
                <span style={appStyles.listRowJibun}>
                  {hasCustomName ? (
                    <>
                      <span style={{ fontWeight: 600, color: '#1A1814', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{row.displayName}</span>
                      <span style={{ color: '#B0ADA5', fontSize: 11, marginLeft: 4, flexShrink: 0, fontFamily: 'IBM Plex Mono, monospace' }}>{row.jibun}</span>
                    </>
                  ) : (
                    <>
                      <span style={{ fontWeight: 500, color: '#1A1814', fontFamily: 'IBM Plex Mono, monospace', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{row.jibun}</span>
                      {duplicateJibuns.has(row.jibun) && (
                        <span style={{ color: '#C4C0B4', fontSize: 10, marginLeft: 4, flexShrink: 0, fontFamily: 'IBM Plex Mono, monospace' }}>#{row.id.toString().slice(-4)}</span>
                      )}
                    </>
                  )}
                </span>

                {/* 색상 뱃지 */}
                <span style={{ width: 76, flexShrink: 0 }}>
                  {colorInfo ? (
                    <span style={appStyles.listColorBadge}>
                      <span style={{ width: 8, height: 8, borderRadius: '50%', background: colorInfo.hex, flexShrink: 0, display: 'inline-block' }}></span>
                      <span style={{ fontSize: 11, color: '#3A3831', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                        {colorLabels[row.colorId] || row.colorId}
                      </span>
                    </span>
                  ) : (
                    <span style={{ color: '#C4C0B4', fontSize: 12 }}>-</span>
                  )}
                </span>

                {/* 면적 */}
                <span style={{ width: 80, flexShrink: 0, textAlign: 'right', fontSize: 12, color: '#5C5851', fontVariantNumeric: 'tabular-nums' }}>
                  {formatArea(row)}
                </span>

                {/* 그룹명 */}
                <span style={{ width: 68, flexShrink: 0, paddingLeft: 10, fontSize: 12, color: '#5C5851', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                  {row.groupName ? row.groupName : <span style={{ color: '#C4C0B4' }}>-</span>}
                </span>
              </button>
            );
          })
        )}
      </div>
    </div>
  );
}
