"use client";

import { useState, useMemo, useCallback } from "react";
import { PageLayout, LoadingState, PageHeader } from "@/components/layout";
import {
  RuleGroupCard,
  RuleCreateDialog,
  RulesSearchBar,
} from "@/components/rules";
import { useBankingMetadata, useTransactions } from "@/lib/hooks";
import { useQueryClient } from "@tanstack/react-query";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Sparkles, RefreshCw } from "lucide-react";
import { updateCategory, autoCategorize } from "@/lib/store-db";
import {
  normalizeDescription,
  suggestKeyword,
} from "@/components/rules/constants";
import type { Transaction } from "@/lib/types";
import {
  invalidateAllTransactionQueries,
  invalidateAllCategoryQueries,
} from "@/lib/cache-utils";

interface TransactionGroup {
  key: string;
  displayName: string;
  transactions: Transaction[];
  totalAmount: number;
  suggestedKeyword: string;
}

export default function RulesPage() {
  const queryClient = useQueryClient();
  const { data: metadata, isLoading: isLoadingMetadata } = useBankingMetadata();

  // Fetch uncategorized transactions only
  const {
    data: transactionsData,
    isLoading: isLoadingTransactions,
  } = useTransactions(
    {
      limit: 10000, // Large limit to get all uncategorized
      offset: 0,
      includeUncategorized: true,
    },
    !!metadata,
  );

  const _refresh = useCallback(() => {
    invalidateAllTransactionQueries(queryClient);
    invalidateAllCategoryQueries(queryClient);
  }, [queryClient]);
  const [searchQuery, setSearchQuery] = useState("");
  const [sortBy, setSortBy] = useState<"count" | "amount" | "name">("count");
  const [filterMinCount, setFilterMinCount] = useState(2);
  const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
  const [selectedGroup, setSelectedGroup] = useState<TransactionGroup | null>(
    null,
  );
  const [isDialogOpen, setIsDialogOpen] = useState(false);
  const [isAutoCategorizing, setIsAutoCategorizing] = useState(false);

  // Group uncategorized transactions by normalized description
  const transactionGroups = useMemo(() => {
    if (!transactionsData?.transactions) return [];

    const uncategorized = transactionsData.transactions;
    const groups: Record<string, Transaction[]> = {};

    uncategorized.forEach((transaction) => {
      const key = normalizeDescription(transaction.description);
      if (!groups[key]) {
        groups[key] = [];
      }
      groups[key].push(transaction);
    });

    // Convert to array with metadata
    const groupArray: TransactionGroup[] = Object.entries(groups).map(
      ([key, transactions]) => {
        const descriptions = transactions.map((t) => t.description);
        return {
          key,
          displayName: transactions[0].description, // Use first transaction's description as display name
          transactions,
          totalAmount: transactions.reduce((sum, t) => sum + t.amount, 0),
          suggestedKeyword: suggestKeyword(descriptions),
        };
      },
    );

    // Filter by search query
    let filtered = groupArray;
    if (searchQuery.trim()) {
      const query = searchQuery.toLowerCase();
      filtered = groupArray.filter(
        (g) =>
          g.displayName.toLowerCase().includes(query) ||
          g.key.includes(query) ||
          g.suggestedKeyword.toLowerCase().includes(query),
      );
    }

    // Filter by minimum count
    filtered = filtered.filter((g) => g.transactions.length >= filterMinCount);

    // Sort
    filtered.sort((a, b) => {
      switch (sortBy) {
        case "count":
          return b.transactions.length - a.transactions.length;
        case "amount":
          return Math.abs(b.totalAmount) - Math.abs(a.totalAmount);
        case "name":
          return a.displayName.localeCompare(b.displayName);
        default:
          return 0;
      }
    });

    return filtered;
  }, [transactionsData?.transactions, searchQuery, sortBy, filterMinCount]);

  const uncategorizedCount = transactionsData?.total || 0;

  const formatCurrency = useCallback((amount: number) => {
    return new Intl.NumberFormat("fr-FR", {
      style: "currency",
      currency: "EUR",
    }).format(amount);
  }, []);

  const formatDate = useCallback((dateStr: string) => {
    return new Date(dateStr).toLocaleDateString("fr-FR", {
      day: "2-digit",
      month: "short",
      year: "numeric",
    });
  }, []);

  const toggleExpand = useCallback((key: string) => {
    setExpandedGroups((prev) => {
      const next = new Set(prev);
      if (next.has(key)) {
        next.delete(key);
      } else {
        next.add(key);
      }
      return next;
    });
  }, []);

  const handleCreateRule = useCallback((group: TransactionGroup) => {
    setSelectedGroup(group);
    setIsDialogOpen(true);
  }, []);

  const handleSaveRule = useCallback(
    async (ruleData: {
      keyword: string;
      categoryId: string;
      applyToExisting: boolean;
      transactionIds: string[];
    }) => {
      if (!metadata) return;

      // 1. Add keyword to category
      const category = metadata.categories.find(
        (c: { id: string }) => c.id === ruleData.categoryId,
      );
      if (!category) {
        throw new Error("Category not found");
      }

      // Check if keyword already exists
      const keywordExists = category.keywords.some(
        (k: string) => k.toLowerCase() === ruleData.keyword.toLowerCase(),
      );

      if (!keywordExists) {
        await updateCategory({
          ...category,
          keywords: [...category.keywords, ruleData.keyword],
        });
      }

      // 2. Apply to existing transactions if requested
      if (ruleData.applyToExisting) {
        await Promise.all(
          ruleData.transactionIds.map((id) =>
            fetch("/api/banking/transactions", {
              method: "PUT",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ id, categoryId: ruleData.categoryId }),
            }),
          ),
        );
      }

      // Invalider toutes les queries liées
      invalidateAllTransactionQueries(queryClient);
      invalidateAllCategoryQueries(queryClient);
    },
    [metadata, queryClient],
  );

  const handleAutoCategorize = useCallback(async () => {
    if (!metadata || !transactionsData) return;

    setIsAutoCategorizing(true);
    try {
      const uncategorized = transactionsData.transactions;
      let categorizedCount = 0;

      for (const transaction of uncategorized) {
        const categoryId = autoCategorize(
          transaction.description + " " + (transaction.memo || ""),
          metadata.categories,
        );
        if (categoryId) {
          await fetch("/api/banking/transactions", {
            method: "PUT",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ ...transaction, categoryId }),
          });
          categorizedCount++;
        }
      }

      // Invalider toutes les queries liées
      invalidateAllTransactionQueries(queryClient);
      invalidateAllCategoryQueries(queryClient);
      alert(
        `${categorizedCount} transaction(s) catégorisée(s) automatiquement`,
      );
    } catch (error) {
      console.error("Error auto-categorizing:", error);
      alert("Erreur lors de la catégorisation automatique");
    } finally {
      setIsAutoCategorizing(false);
    }
  }, [metadata, transactionsData, queryClient]);

  const handleCategorizeGroup = useCallback(
    async (group: TransactionGroup, categoryId: string | null) => {
      try {
        await Promise.all(
          group.transactions.map((t) =>
            fetch("/api/banking/transactions", {
              method: "PUT",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ ...t, categoryId }),
            }),
          ),
        );
        // Invalider toutes les queries liées
        invalidateAllTransactionQueries(queryClient);
        invalidateAllCategoryQueries(queryClient);
      } catch (error) {
        console.error("Error categorizing group:", error);
        alert("Erreur lors de la catégorisation");
      }
    },
    [queryClient],
  );

  if (
    isLoadingMetadata ||
    !metadata ||
    isLoadingTransactions ||
    !transactionsData
  ) {
    return <LoadingState />;
  }

  return (
    <PageLayout>
      <PageHeader
        title="Règles de catégorisation"
        description={
          <span className="flex items-center gap-2 flex-wrap">
            <span className="text-xs md:text-base">
              {transactionGroups.length} groupe
              {transactionGroups.length > 1 ? "s" : ""} de transactions
              similaires
            </span>
            <Badge variant="secondary" className="text-[10px] md:text-xs">
              {uncategorizedCount} non catégorisées
            </Badge>
          </span>
        }
        actions={
          uncategorizedCount > 0 && (
            <Button
              variant="outline"
              onClick={handleAutoCategorize}
              disabled={isAutoCategorizing}
            >
              {isAutoCategorizing ? (
                <RefreshCw className="h-4 w-4 mr-2 animate-spin" />
              ) : (
                <Sparkles className="h-4 w-4 mr-2" />
              )}
              Auto-catégoriser
            </Button>
          )
        }
      />

      <RulesSearchBar
        searchQuery={searchQuery}
        onSearchChange={setSearchQuery}
        sortBy={sortBy}
        onSortChange={setSortBy}
        filterMinCount={filterMinCount}
        onFilterMinCountChange={setFilterMinCount}
      />

      {transactionGroups.length === 0 ? (
        <div className="flex flex-col items-center justify-center py-12 md:py-16 text-center px-4">
          <Sparkles className="h-8 w-8 md:h-12 md:w-12 text-muted-foreground mb-3 md:mb-4" />
          <h3 className="text-base md:text-lg font-medium text-foreground mb-2">
            {uncategorizedCount === 0
              ? "Toutes les transactions sont catégorisées !"
              : "Aucun groupe trouvé"}
          </h3>
          <p className="text-xs md:text-sm text-muted-foreground max-w-md">
            {uncategorizedCount === 0
              ? "Continuez à importer des transactions pour voir les suggestions de règles."
              : filterMinCount > 1
                ? `Essayez de réduire le filtre minimum à ${filterMinCount - 1}+ transactions.`
                : "Modifiez vos critères de recherche."}
          </p>
        </div>
      ) : (
        <div className="space-y-2 md:space-y-3">
          {transactionGroups.map((group) => (
            <RuleGroupCard
              key={group.key}
              group={group}
              isExpanded={expandedGroups.has(group.key)}
              onToggleExpand={() => toggleExpand(group.key)}
              onCreateRule={() => handleCreateRule(group)}
              onCategorize={(categoryId) =>
                handleCategorizeGroup(group, categoryId)
              }
              categories={metadata.categories}
              formatCurrency={formatCurrency}
              formatDate={formatDate}
            />
          ))}
        </div>
      )}

      <RuleCreateDialog
        open={isDialogOpen}
        onOpenChange={setIsDialogOpen}
        group={selectedGroup}
        categories={metadata.categories}
        onSave={handleSaveRule}
      />
    </PageLayout>
  );
}
