"use client";

import { useMemo, useState, useCallback } from "react";
import { ProcessedReceipt } from "@/lib/schema/receipt";
import { grossOf } from "@/components/dashboard/receiptFormat";
import { resolveReceiptStatusTier } from "@/components/dashboard/StatusBadge";

export type TemporalPeriod =
  | "all"
  | "today"
  | "week"
  | "month"
  | "last_30_days"
  | "last_60_days"
  | "last_90_days"
  | "year"
  | "custom"
  | string;

export interface DateRange {
  from?: string | null;
  to?: string | null;
}

export interface AmountRange {
  min?: number | null;
  max?: number | null;
}

export interface UseReceiptFiltersOptions {
  receipts: ProcessedReceipt[];
  initialPeriod?: TemporalPeriod | string;
  initialCustomDateRange?: DateRange;
  initialStatus?: string;
  initialCategory?: string;
  initialSearchQuery?: string;
  initialAmountRange?: AmountRange;
}

export interface UseReceiptFiltersReturn {
  /** Array of receipts matching all active filter criteria */
  filteredReceipts: ProcessedReceipt[];
  /** Active temporal period */
  activePeriod: TemporalPeriod | string;
  setPeriod: (period: TemporalPeriod | string) => void;
  /** Custom date range for period === "custom" */
  customDateRange: DateRange;
  setCustomDateRange: React.Dispatch<React.SetStateAction<DateRange>>;
  /** Active status filter */
  activeStatus: string;
  setStatus: (status: string) => void;
  /** Active category filter */
  activeCategory: string;
  setCategory: (category: string) => void;
  /** Active search query string */
  searchQuery: string;
  setSearchQuery: (query: string) => void;
  /** Active gross amount range */
  amountRange: AmountRange;
  setAmountRange: React.Dispatch<React.SetStateAction<AmountRange>>;
  /** Reset all filters to defaults */
  resetFilters: () => void;
  /** Whether any non-default filter is currently active */
  hasActiveFilters: boolean;
  /** Total count of active non-default filters */
  activeFilterCount: number;
  /** Status counters for all receipts */
  statusCounts: {
    all: number;
    scanned: number;
    pending: number;
    confirmed: number;
  };
  /** Category distribution for all receipts */
  categoryCounts: Record<string, number>;
}

/**
 * Checks if a given date string falls within the temporal period
 */
export function isDateInPeriod(
  isoDate: string | null | undefined,
  period: TemporalPeriod | string,
  customRange?: DateRange
): boolean {
  if (!period || period === "all") return true;
  if (!isoDate) return false;

  const date = new Date(isoDate);
  if (isNaN(date.getTime())) return false;

  const now = new Date();
  const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
  const endOfToday = startOfToday + 86400000 - 1;
  const dateTime = date.getTime();

  switch (period) {
    case "today":
      return dateTime >= startOfToday && dateTime <= endOfToday;

    case "week": {
      // Calculate Monday of current week
      const currentDayOfWeek = (now.getDay() + 6) % 7; // 0 = Monday, 6 = Sunday
      const monday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - currentDayOfWeek, 0, 0, 0, 0);
      const sunday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - currentDayOfWeek + 6, 23, 59, 59, 999);
      return dateTime >= monday.getTime() && dateTime <= sunday.getTime();
    }

    case "month":
      return date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth();

    case "year":
      return date.getFullYear() === now.getFullYear();

    case "last_30_days": {
      const past30 = startOfToday - 29 * 86400000;
      return dateTime >= past30 && dateTime <= endOfToday;
    }

    case "last_60_days": {
      const past60 = startOfToday - 59 * 86400000;
      return dateTime >= past60 && dateTime <= endOfToday;
    }

    case "last_90_days": {
      const past90 = startOfToday - 89 * 86400000;
      return dateTime >= past90 && dateTime <= endOfToday;
    }

    case "custom": {
      if (customRange?.from && isoDate < customRange.from) return false;
      if (customRange?.to && isoDate > customRange.to) return false;
      return true;
    }

    default:
      // If a specific period key like "2026-08" or "2026-Q3" is passed
      if (typeof period === "string") {
        return isoDate.startsWith(period);
      }
      return true;
  }
}

export function useReceiptFilters(
  receipts: ProcessedReceipt[] = [],
  options: Partial<UseReceiptFiltersOptions> = {}
): UseReceiptFiltersReturn {
  const [activePeriod, setActivePeriod] = useState<TemporalPeriod | string>(
    options.initialPeriod ?? "all"
  );
  const [customDateRange, setCustomDateRange] = useState<DateRange>(
    options.initialCustomDateRange ?? { from: null, to: null }
  );
  const [activeStatus, setActiveStatus] = useState<string>(
    options.initialStatus ?? "all"
  );
  const [activeCategory, setActiveCategory] = useState<string>(
    options.initialCategory ?? "all"
  );
  const [searchQuery, setSearchQuery] = useState<string>(
    options.initialSearchQuery ?? ""
  );
  const [amountRange, setAmountRange] = useState<AmountRange>(
    options.initialAmountRange ?? { min: null, max: null }
  );

  const resetFilters = useCallback(() => {
    setActivePeriod("all");
    setCustomDateRange({ from: null, to: null });
    setActiveStatus("all");
    setActiveCategory("all");
    setSearchQuery("");
    setAmountRange({ min: null, max: null });
  }, []);

  const hasActiveFilters = useMemo(() => {
    return (
      activePeriod !== "all" ||
      customDateRange.from != null ||
      customDateRange.to != null ||
      activeStatus !== "all" ||
      activeCategory !== "all" ||
      searchQuery.trim() !== "" ||
      amountRange.min != null ||
      amountRange.max != null
    );
  }, [activePeriod, customDateRange, activeStatus, activeCategory, searchQuery, amountRange]);

  const activeFilterCount = useMemo(() => {
    let count = 0;
    if (activePeriod !== "all") count++;
    if (activeStatus !== "all") count++;
    if (activeCategory !== "all") count++;
    if (searchQuery.trim() !== "") count++;
    if (amountRange.min != null || amountRange.max != null) count++;
    return count;
  }, [activePeriod, activeStatus, activeCategory, searchQuery, amountRange]);

  // Overall counts for badges
  const statusCounts = useMemo(() => {
    let scanned = 0;
    let pending = 0;
    let confirmed = 0;

    for (const r of receipts) {
      const tier = resolveReceiptStatusTier(r);
      if (tier === "pending_review") {
        pending++;
      } else if (tier === "confirmed") {
        confirmed++;
      } else {
        scanned++;
      }
    }

    return {
      all: receipts.length,
      scanned,
      pending,
      confirmed,
    };
  }, [receipts]);

  const categoryCounts = useMemo(() => {
    const counts: Record<string, number> = {};
    for (const r of receipts) {
      const cat = r.suggestedCategory || "Sonstiges";
      counts[cat] = (counts[cat] || 0) + 1;
    }
    return counts;
  }, [receipts]);

  const filteredReceipts = useMemo(() => {
    const query = searchQuery.trim().toLowerCase();

    return receipts.filter((receipt) => {
      // 1. Temporal Period Filter
      if (activePeriod !== "all") {
        if (!isDateInPeriod(receipt.date?.isoDate, activePeriod, customDateRange)) {
          return false;
        }
      }

      // 2. Status Filter
      if (activeStatus !== "all") {
        const tier = resolveReceiptStatusTier(receipt);
        const normalizedTarget = activeStatus.toLowerCase();

        if (normalizedTarget === "pending" || normalizedTarget === "pending_review" || normalizedTarget === "pruefen") {
          if (tier !== "pending_review") return false;
        } else if (normalizedTarget === "confirmed" || normalizedTarget === "bestaetigt") {
          if (tier !== "confirmed") return false;
        } else if (normalizedTarget === "scanned" || normalizedTarget === "erfasst" || normalizedTarget === "ready") {
          if (tier !== "scanned") return false;
        }
      }

      // 3. Category Filter
      if (activeCategory !== "all") {
        if (receipt.suggestedCategory !== activeCategory) {
          return false;
        }
      }

      // 4. Amount Range Filter
      const gross = grossOf(receipt);
      if (amountRange.min != null && !isNaN(amountRange.min)) {
        if (gross < amountRange.min) return false;
      }
      if (amountRange.max != null && !isNaN(amountRange.max)) {
        if (gross > amountRange.max) return false;
      }

      // 5. Search Query Filter
      if (query) {
        const merchantName = (receipt.merchant?.name ?? "").toLowerCase();
        const merchantAddress = (receipt.merchant?.address ?? "").toLowerCase();
        const receiptNo = (receipt.receiptNumber ?? "").toLowerCase();
        const isoDate = (receipt.date?.isoDate ?? "").toLowerCase();
        const category = (receipt.suggestedCategory ?? "").toLowerCase();
        const docType = (receipt.documentType ?? "").toLowerCase();
        const paymentMethod = (receipt.paymentMethod ?? "").toLowerCase();
        const grossStr = gross.toFixed(2);
        const grossStrDe = grossStr.replace(".", ",");

        const lineItemsMatch = receipt.lineItems?.some((item) =>
          item?.description?.toLowerCase().includes(query)
        );

        const matches =
          merchantName.includes(query) ||
          merchantAddress.includes(query) ||
          receiptNo.includes(query) ||
          isoDate.includes(query) ||
          category.includes(query) ||
          docType.includes(query) ||
          paymentMethod.includes(query) ||
          grossStr.includes(query) ||
          grossStrDe.includes(query) ||
          lineItemsMatch;

        if (!matches) return false;
      }

      return true;
    });
  }, [receipts, activePeriod, customDateRange, activeStatus, activeCategory, amountRange, searchQuery]);

  return {
    filteredReceipts,
    activePeriod,
    setPeriod: setActivePeriod,
    customDateRange,
    setCustomDateRange,
    activeStatus,
    setStatus: setActiveStatus,
    activeCategory,
    setCategory: setActiveCategory,
    searchQuery,
    setSearchQuery,
    amountRange,
    setAmountRange,
    resetFilters,
    hasActiveFilters,
    activeFilterCount,
    statusCounts,
    categoryCounts,
  };
}
