import { create } from "zustand";
import { apiFetch } from "../lib/api";

export type BlockerStats = {
  current: number;
  weeklyAdded: number;
  monthlyAdded: number;
  history: { label: string; count: number }[];
  submissions: {
    inReview: number;
    approved: number;
    rejected: number;
  };
  mySubmissions: {
    inReview: number;
    approved: number;
    rejected: number;
  };
  avgPerUser: number;
  avgApprovalWaitDays: number;
};

type RawStatsResponse = {
  current?: unknown;
  weeklyAdded?: unknown;
  monthlyAdded?: unknown;
  history?: Array<{ label?: unknown; count?: unknown }>;
  submissions?: {
    inVote?: unknown;
    inReview?: unknown;
    pending?: unknown;
    approved?: unknown;
    rejected?: unknown;
  };
  mySubmissions?: {
    active?: unknown;
    inVote?: unknown;
    inReview?: unknown;
    pending?: unknown;
    approved?: unknown;
    rejected?: unknown;
  };
  avgPerUser?: unknown;
  avgApprovalWaitDays?: unknown;
};

type BlockerStatsState = {
  stats: BlockerStats | null;
  loading: boolean;
  error: string | null;
  fetchedAt: number | null;
  refresh: () => Promise<void>;
  refreshIfStale: (maxAgeMs?: number) => Promise<void>;
  /** Optimistische lokale Erhöhung von mySubmissions.inReview — damit das Half-Donut
   *  im ProtectionDetailsSheet sofort die neue Freigabe zeigt, ohne auf den
   *  60s-Cache-Refresh zu warten. Der nächste echte refresh() überschreibt den Wert
   *  ohnehin mit dem Server-State. */
  bumpMyInReview: (delta?: number) => void;
};

let inFlight: Promise<void> | null = null;

function asNumber(value: unknown): number {
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
}

function normalizeStats(raw: RawStatsResponse): BlockerStats {
  const inReviewGlobal =
    asNumber(raw.submissions?.inReview) +
    asNumber(raw.submissions?.inVote) +
    asNumber(raw.submissions?.pending);

  const inReviewMine =
    asNumber(raw.mySubmissions?.inReview) +
    asNumber(raw.mySubmissions?.inVote) +
    asNumber(raw.mySubmissions?.pending);

  const approvedMine =
    asNumber(raw.mySubmissions?.approved) + asNumber(raw.mySubmissions?.active);

  const history = Array.isArray(raw.history)
    ? raw.history.map((h) => ({
        label: typeof h?.label === "string" ? h.label : "",
        count: asNumber(h?.count),
      }))
    : [];

  return {
    current: asNumber(raw.current),
    weeklyAdded: asNumber(raw.weeklyAdded),
    monthlyAdded: asNumber(raw.monthlyAdded),
    history,
    submissions: {
      inReview: inReviewGlobal,
      approved: asNumber(raw.submissions?.approved),
      rejected: asNumber(raw.submissions?.rejected),
    },
    mySubmissions: {
      inReview: inReviewMine,
      approved: approvedMine,
      rejected: asNumber(raw.mySubmissions?.rejected),
    },
    avgPerUser: asNumber(raw.avgPerUser),
    avgApprovalWaitDays: asNumber(raw.avgApprovalWaitDays),
  };
}

export const useBlockerStatsStore = create<BlockerStatsState>((set, get) => ({
  stats: null,
  loading: false,
  error: null,
  fetchedAt: null,

  refresh: async () => {
    if (inFlight) return inFlight;

    inFlight = (async () => {
      set((s) => ({ ...s, loading: true, error: null }));
      try {
        const raw = await apiFetch<RawStatsResponse>("/api/blocklist/stats");
        const stats = normalizeStats(raw ?? {});
        set({ stats, loading: false, error: null, fetchedAt: Date.now() });
      } catch (e: any) {
        set((s) => ({
          ...s,
          loading: false,
          error: e?.message ?? "stats_fetch_failed",
        }));
      } finally {
        inFlight = null;
      }
    })();

    return inFlight;
  },

  refreshIfStale: async (maxAgeMs = 60_000) => {
    const { fetchedAt, stats, refresh } = get();
    if (!stats || !fetchedAt || Date.now() - fetchedAt > maxAgeMs) {
      await refresh();
    }
  },

  bumpMyInReview: (delta = 1) => {
    const { stats } = get();
    if (!stats) return;
    set({
      stats: {
        ...stats,
        mySubmissions: {
          ...stats.mySubmissions,
          inReview: Math.max(0, stats.mySubmissions.inReview + delta),
        },
        submissions: {
          ...stats.submissions,
          inReview: Math.max(0, stats.submissions.inReview + delta),
        },
      },
    });
  },
}));
