import { create } from 'zustand';
import { patientApi } from '../api/health/patients';
import { doctorApi } from '../api/health/doctors';

interface HealthState {
  patientNames: Record<string, string>;
  doctorNames: Record<string, string>;
  loadingIds: Set<string>;

  resolvePatientName: (id: string) => Promise<string>;
  resolveDoctorName: (id: string) => Promise<string>;
  getPatientName: (id: string) => string;
  getDoctorName: (id: string) => string;
  batchResolvePatientNames: (ids: string[]) => Promise<void>;
  batchResolveDoctorNames: (ids: string[]) => Promise<void>;
}

export const useHealthStore = create<HealthState>((set, get) => ({
  patientNames: {},
  doctorNames: {},
  loadingIds: new Set(),

  resolvePatientName: async (id: string) => {
    const { patientNames, loadingIds } = get();
    if (patientNames[id]) return patientNames[id];
    if (loadingIds.has(`p:${id}`)) return id.slice(0, 8);

    const newLoading = new Set(loadingIds);
    newLoading.add(`p:${id}`);
    set({ loadingIds: newLoading });

    try {
      const detail = await patientApi.get(id);
      const name = detail.name;
      set((s) => ({
        patientNames: { ...s.patientNames, [id]: name },
        loadingIds: new Set([...s.loadingIds].filter((k) => k !== `p:${id}`)),
      }));
      return name;
    } catch {
      set((s) => ({
        patientNames: { ...s.patientNames, [id]: id.slice(0, 8) },
        loadingIds: new Set([...s.loadingIds].filter((k) => k !== `p:${id}`)),
      }));
      return id.slice(0, 8);
    }
  },

  resolveDoctorName: async (id: string) => {
    const { doctorNames, loadingIds } = get();
    if (doctorNames[id]) return doctorNames[id];
    if (loadingIds.has(`d:${id}`)) return id.slice(0, 8);

    const newLoading = new Set(loadingIds);
    newLoading.add(`d:${id}`);
    set({ loadingIds: newLoading });

    try {
      const detail = await doctorApi.get(id);
      const name = detail.name;
      set((s) => ({
        doctorNames: { ...s.doctorNames, [id]: name },
        loadingIds: new Set([...s.loadingIds].filter((k) => k !== `d:${id}`)),
      }));
      return name;
    } catch {
      set((s) => ({
        doctorNames: { ...s.doctorNames, [id]: id.slice(0, 8) },
        loadingIds: new Set([...s.loadingIds].filter((k) => k !== `d:${id}`)),
      }));
      return id.slice(0, 8);
    }
  },

  getPatientName: (id: string) => get().patientNames[id] || id.slice(0, 8),
  getDoctorName: (id: string) => get().doctorNames[id] || id.slice(0, 8),

  batchResolvePatientNames: async (ids: string[]) => {
    const { patientNames } = get();
    const uniqueIds = [...new Set(ids)];
    const missing = uniqueIds.filter((id) => !patientNames[id]);
    if (missing.length === 0) return;

    const limit = 5;
    for (let i = 0; i < missing.length; i += limit) {
      const batch = missing.slice(i, i + limit);
      const results = await Promise.allSettled(
        batch.map(async (id) => {
          const detail = await patientApi.get(id);
          return { id, name: detail.name };
        }),
      );
      const newEntries: Record<string, string> = {};
      results.forEach((r, idx) => {
        newEntries[batch[idx]] = r.status === 'fulfilled' ? r.value.name : batch[idx].slice(0, 8);
      });
      set((s) => ({ patientNames: { ...s.patientNames, ...newEntries } }));
    }
  },

  batchResolveDoctorNames: async (ids: string[]) => {
    const { doctorNames } = get();
    const uniqueIds = [...new Set(ids)];
    const missing = uniqueIds.filter((id) => !doctorNames[id]);
    if (missing.length === 0) return;

    const limit = 5;
    for (let i = 0; i < missing.length; i += limit) {
      const batch = missing.slice(i, i + limit);
      const results = await Promise.allSettled(
        batch.map(async (id) => {
          const detail = await doctorApi.get(id);
          return { id, name: detail.name };
        }),
      );
      const newEntries: Record<string, string> = {};
      results.forEach((r, idx) => {
        newEntries[batch[idx]] = r.status === 'fulfilled' ? r.value.name : batch[idx].slice(0, 8);
      });
      set((s) => ({ doctorNames: { ...s.doctorNames, ...newEntries } }));
    }
  },
}));
