"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useSearchParams } from "next/navigation";
import {
  boardParams,
  fetchAttendanceFilters,
  type BoardQuery,
  type DeliveryFilter,
  type FilterOptions,
  type ListFilter,
  type SmsFilter,
  type StudentStatusFilter,
} from "@/lib/attendance-report";
import { ApiError } from "@/lib/api";
import { getActiveBranchId } from "@/lib/session-context";
import {
  isRangePreset,
  rangeLabel,
  resolveRange,
  shiftDays,
  type DateRangePreset,
} from "./dateRange";

export const DASHBOARD_PATH = "/academic/attendance";
export const RECORDS_PATH = "/academic/attendance/records";

export type RecordsDataset = "students" | "classes" | "alerts";

export interface AttendanceFilterState {
  /** خالی یعنی «همهٔ شعب در دسترس»؛ سرور خودش محدوده را می‌بندد. */
  branchIds: number[];
  preset: DateRangePreset;
  customFrom: string;
  customTo: string;
  deliveryMode: DeliveryFilter;
  periodId: number | null;
  gradeLevelId: number | null;
  classRoomId: number | null;
  teacherId: number | null;
  status: StudentStatusFilter;
  lists: ListFilter;
  sms: SmsFilter;
  q: string;
}

const EMPTY_OPTIONS: FilterOptions = {
  branches: [],
  periods: [],
  grade_levels: [],
  class_rooms: [],
  delivery_modes: [{ key: "all", label: "حضوری و مجازی" }],
  statuses: [],
  sms_states: [],
  today: "",
};

function localToday(): string {
  const now = new Date();
  const offset = now.getTimezoneOffset() * 60000;
  return new Date(now.getTime() - offset).toISOString().slice(0, 10);
}

function numberParam(raw: string | null): number | null {
  const value = Number(raw);
  return raw && Number.isFinite(value) && value > 0 ? value : null;
}

function listParam(raw: string | null): number[] {
  if (!raw || raw === "all") return [];
  return raw
    .split(",")
    .map((part) => Number(part.trim()))
    .filter((id) => Number.isFinite(id) && id > 0);
}

/**
 * وضعیت فیلترهای گزارش حضور و غیاب.
 *
 * همهٔ گزینه‌ها از `attendance/board/filters` می‌آید، پس هیچ لیست ثابتی در
 * کلاینت نگه داشته نمی‌شود. مقدار اولیه از query string خوانده می‌شود تا
 * لینک‌های داشبورد → ریز داده‌ها بازه و محدودهٔ خودشان را حفظ کنند.
 */
export function useAttendanceFilters() {
  const search = useSearchParams();

  const [state, setState] = useState<AttendanceFilterState>(() => {
    const activeBranch = getActiveBranchId();
    const urlBranches = listParam(search.get("branch_id"));
    const presetRaw = search.get("range");
    const from = search.get("from");
    const to = search.get("to");
    const today = localToday();

    return {
      branchIds:
        urlBranches.length > 0 ? urlBranches : activeBranch ? [Number(activeBranch)] : [],
      preset: isRangePreset(presetRaw) ? presetRaw : from || to ? "custom" : "today",
      customFrom: from ?? shiftDays(today, -6),
      customTo: to ?? today,
      deliveryMode: (search.get("delivery_mode") as DeliveryFilter | null) ?? "all",
      periodId: numberParam(search.get("period_id")),
      gradeLevelId: numberParam(search.get("grade_level_id")),
      classRoomId: numberParam(search.get("class_room_id")),
      teacherId: numberParam(search.get("teacher_id")),
      status: (search.get("status") as StudentStatusFilter | null) ?? "all",
      lists: (search.get("lists") as ListFilter | null) ?? "all",
      sms: (search.get("sms") as SmsFilter | null) ?? "all",
      q: search.get("q") ?? "",
    };
  });

  const [options, setOptions] = useState<FilterOptions>(EMPTY_OPTIONS);
  const [optionsError, setOptionsError] = useState<string | null>(null);
  const [optionsLoading, setOptionsLoading] = useState(true);
  const [serverToday, setServerToday] = useState<string>(() => localToday());

  const range = useMemo(
    () =>
      resolveRange(state.preset, serverToday, {
        from: state.customFrom,
        to: state.customTo,
      }),
    [state.preset, state.customFrom, state.customTo, serverToday],
  );

  /** محدودهٔ مشترک همهٔ درخواست‌ها؛ فیلترهای ردیفی جدا اضافه می‌شوند. */
  const scopeQuery = useMemo<BoardQuery>(
    () => ({
      from: range.from,
      to: range.to,
      branchIds: state.branchIds,
      deliveryMode: state.deliveryMode,
      periodId: state.periodId,
      gradeLevelId: state.gradeLevelId,
      classRoomId: state.classRoomId,
      teacherId: state.teacherId,
    }),
    [
      range.from,
      range.to,
      state.branchIds,
      state.deliveryMode,
      state.periodId,
      state.gradeLevelId,
      state.classRoomId,
      state.teacherId,
    ],
  );

  const scopeKey = useMemo(
    () => new URLSearchParams(boardParams(scopeQuery)).toString(),
    [scopeQuery],
  );

  useEffect(() => {
    let cancelled = false;
    setOptionsLoading(true);
    fetchAttendanceFilters(scopeQuery)
      .then((data) => {
        if (cancelled) return;
        setOptions(data);
        setOptionsError(null);
        if (data.today) setServerToday(data.today);
      })
      .catch((error: unknown) => {
        if (cancelled) return;
        setOptionsError(
          error instanceof ApiError ? error.message : "خطا در دریافت گزینه‌های فیلتر",
        );
      })
      .finally(() => {
        if (!cancelled) setOptionsLoading(false);
      });
    return () => {
      cancelled = true;
    };
    // scopeKey نمایندهٔ محتوای scopeQuery است و از رفرش بی‌مورد جلوگیری می‌کند.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [scopeKey]);

  const patch = useCallback((changes: Partial<AttendanceFilterState>) => {
    setState((prev) => ({ ...prev, ...changes }));
  }, []);

  const setCustomRange = useCallback((from: string, to: string) => {
    setState((prev) => ({ ...prev, preset: "custom", customFrom: from, customTo: to }));
  }, []);

  const resetRowFilters = useCallback(() => {
    setState((prev) => ({ ...prev, status: "all", lists: "all", sms: "all", q: "" }));
  }, []);

  const branchLabel = useMemo(() => {
    if (options.branches.length === 0) return "در حال بارگذاری…";
    const selected =
      state.branchIds.length === 0
        ? options.branches
        : options.branches.filter((branch) => state.branchIds.includes(branch.id));
    if (selected.length === 0) return "شعبه‌ای در دسترس نیست";
    if (selected.length === options.branches.length) {
      return options.branches.length === 1 ? selected[0].name : "تمام مجموعه";
    }
    if (selected.length <= 2) return selected.map((branch) => branch.name).join("، ");
    return `${selected[0].name} و ${(selected.length - 1).toLocaleString("fa-IR")} شعبه دیگر`;
  }, [options.branches, state.branchIds]);

  const dateLabel = useMemo(() => rangeLabel(state.preset, range), [state.preset, range]);

  /** لینک پایدار به ریز داده‌ها با حفظ همین محدوده. */
  const hrefFor = useCallback(
    (
      params: {
        dataset?: RecordsDataset;
        status?: StudentStatusFilter;
        lists?: ListFilter;
        sms?: SmsFilter;
        branchIds?: number[];
        deliveryMode?: DeliveryFilter;
        periodId?: number | null;
        classRoomId?: number | null;
        teacherId?: number | null;
      } = {},
      path: string = RECORDS_PATH,
    ) => {
      const query = new URLSearchParams();
      const branchIds = params.branchIds ?? state.branchIds;
      if (params.dataset && params.dataset !== "students") query.set("dataset", params.dataset);
      if (branchIds.length > 0) query.set("branch_id", branchIds.join(","));
      query.set("range", state.preset);
      if (state.preset === "custom") {
        query.set("from", range.from);
        query.set("to", range.to);
      }
      const delivery = params.deliveryMode ?? state.deliveryMode;
      if (delivery && delivery !== "all") query.set("delivery_mode", delivery);
      const periodId = params.periodId ?? state.periodId;
      if (periodId) query.set("period_id", String(periodId));
      if (state.gradeLevelId) query.set("grade_level_id", String(state.gradeLevelId));
      const classRoomId = params.classRoomId ?? state.classRoomId;
      if (classRoomId) query.set("class_room_id", String(classRoomId));
      const teacherId = params.teacherId ?? state.teacherId;
      if (teacherId) query.set("teacher_id", String(teacherId));
      if (params.status && params.status !== "all") query.set("status", params.status);
      if (params.lists && params.lists !== "all") query.set("lists", params.lists);
      if (params.sms && params.sms !== "all") query.set("sms", params.sms);
      if (state.q.trim()) query.set("q", state.q.trim());

      const qs = query.toString();
      return qs ? `${path}?${qs}` : path;
    },
    [state, range],
  );

  return {
    state,
    patch,
    setCustomRange,
    resetRowFilters,
    options,
    optionsLoading,
    optionsError,
    today: serverToday,
    range,
    scopeQuery,
    scopeKey,
    branchLabel,
    dateLabel,
    hrefFor,
  };
}

export type AttendanceFilters = ReturnType<typeof useAttendanceFilters>;
