'use client';

import { useCallback, useEffect, useRef, useState } from 'react';
import type { ListPlansQuery, PlanListItem } from '@pac/types';
import { plansApi } from './plans-api';

const PAGE_SIZE = 25;

/** 左栏选人列表的服务端筛选(全部上后端,跨全表)。 */
export interface PickerFilters {
  view: 'pool' | 'mine' | 'all';
  keyword?: string;
  sort: 'priority_desc' | 'priority_asc' | 'created_desc';
  phoneVerified?: true;
  /** 诊所多选(target_clinic_id IN) */
  targetClinicIds?: string[];
  /** "key:value" 逗号串(PERSONA_TAG_FILTER_DIMS 维度) */
  personaTags?: string;
}

export interface UsePatientPicker {
  items: PlanListItem[];
  total: number;
  loading: boolean;
  hasMore: boolean;
  error: string | null;
  loadMore: () => void;
  refresh: () => void;
  /** 原地更新一条(如认领后改状态),不重拉、不丢滚动位置 */
  patchItem: (id: string, patch: Partial<PlanListItem>) => void;
  /** 原地移除一条(如认领/返池后该行已不属于当前 tab),同步减 total,不重拉 */
  removeItem: (id: string) => void;
}

/**
 * 详情页左栏"选患者"列表 — 服务端分页 + 触底累加;筛选变化自动回第一页重拉。
 * (use-my-tasks 的泛化版:不只 mine,带全套筛选)
 */
export function usePatientPicker(filters: PickerFilters): UsePatientPicker {
  const [items, setItems] = useState<PlanListItem[]>([]);
  const [total, setTotal] = useState(0);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const loadingRef = useRef(false);
  // 筛选签名:变了 → 重置回第一页
  const sig = JSON.stringify(filters);

  const fetchPage = useCallback(
    async (p: number) => {
      if (loadingRef.current) return;
      loadingRef.current = true;
      setLoading(true);
      setError(null);
      try {
        const q: Partial<ListPlansQuery> = {
          view: filters.view,
          // 「我的」= 我手头进行中的活(assigned)。服务端 view=mine 返回我名下全部状态
          // (为旧列表页子 tab 设计),不显式过滤会把已结案/已放弃也列出来 —— 与召回池
          // (服务端硬过滤 active)口径对齐,终态单不进工作台左栏。
          status: filters.view === 'mine' ? 'assigned' : undefined,
          keyword: filters.keyword || undefined,
          sort: filters.sort,
          phoneVerified: filters.phoneVerified,
          targetClinicIds: filters.targetClinicIds?.length ? filters.targetClinicIds : undefined,
          personaTags: filters.personaTags || undefined,
          page: p,
          pageSize: PAGE_SIZE,
        };
        const data = await plansApi.list(q);
        setTotal(data.total);
        setItems((prev) => {
          if (p === 1) return data.items;
          const seen = new Set(prev.map((x) => x.id));
          return [...prev, ...data.items.filter((x) => !seen.has(x.id))];
        });
        setPage(p);
      } catch (err) {
        setError(err instanceof Error ? err.message : String(err));
      } finally {
        loadingRef.current = false;
        setLoading(false);
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [sig],
  );

  useEffect(() => {
    setItems([]);
    setTotal(0);
    setPage(1);
    void fetchPage(1);
  }, [fetchPage]);

  const hasMore = items.length < total;
  const loadMore = useCallback(() => {
    if (loadingRef.current || !hasMore) return;
    void fetchPage(page + 1);
  }, [fetchPage, hasMore, page]);

  const refresh = useCallback(() => {
    void fetchPage(1);
  }, [fetchPage]);

  const patchItem = useCallback((id: string, patch: Partial<PlanListItem>) => {
    setItems((prev) => prev.map((x) => (x.id === id ? { ...x, ...patch } : x)));
  }, []);

  const removeItem = useCallback((id: string) => {
    setItems((prev) => {
      const next = prev.filter((x) => x.id !== id);
      if (next.length !== prev.length) setTotal((t) => Math.max(0, t - 1));
      return next;
    });
  }, []);

  return { items, total, loading, hasMore, error, loadMore, refresh, patchItem, removeItem };
}
