"use client";

import { useState, useMemo, useEffect, useCallback } from "react";
import { PageLayout, LoadingState, PageHeader } from "@/components/layout";
import {
  CategoryCard,
  CategoryEditDialog,
  ParentCategoryRow,
  CategorySearchBar,
} from "@/components/categories";
import { useBankingMetadata, useCategoryStats } from "@/lib/hooks";
import { useQueryClient } from "@tanstack/react-query";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
} from "@/components/ui/dialog";
import { Badge } from "@/components/ui/badge";
import { CategoryIcon } from "@/components/ui/category-icon";
import { Plus, ArrowRight, CheckCircle2, RefreshCw } from "lucide-react";
import {
  autoCategorize,
  addCategory,
  updateCategory,
  deleteCategory,
} from "@/lib/store-db";
import type { Category, Transaction } from "@/lib/types";
import { invalidateAllCategoryQueries } from "@/lib/cache-utils";
import { useLocalStorage } from "@/hooks/use-local-storage";

interface RecategorizationResult {
  transaction: Transaction;
  category: Category;
}

export default function CategoriesPage() {
  const queryClient = useQueryClient();
  const { data: metadata, isLoading: isLoadingMetadata } = useBankingMetadata();
  const { data: categoryStats, isLoading: isLoadingStats } = useCategoryStats();
  const [isDialogOpen, setIsDialogOpen] = useState(false);
  const [editingCategory, setEditingCategory] = useState<Category | null>(null);
  const [expandedParents, setExpandedParents] = useState<Set<string>>(
    new Set()
  );
  const [formData, setFormData] = useState({
    name: "",
    color: "#22c55e",
    icon: "tag",
    keywords: [] as string[],
    parentId: null as string | null,
  });
  const [searchQuery, setSearchQuery] = useState("");
  const [recatResults, setRecatResults] = useState<RecategorizationResult[]>(
    []
  );
  const [isRecatDialogOpen, setIsRecatDialogOpen] = useState(false);
  const [isRecategorizing, setIsRecategorizing] = useState(false);

  // Persister l'état "tout déplier" dans le localStorage
  const [expandAllByDefault, setExpandAllByDefault] = useLocalStorage(
    "categories-expand-all-by-default",
    true
  );

  // Organiser les catégories par parent
  const { parentCategories, childrenByParent, orphanCategories } =
    useMemo(() => {
      if (!metadata?.categories)
        return {
          parentCategories: [],
          childrenByParent: {},
          orphanCategories: [],
        };

      const parents = metadata.categories.filter(
        (c: Category) => c.parentId === null
      );
      const children: Record<string, Category[]> = {};
      const orphans: Category[] = [];

      metadata.categories
        .filter((c: Category) => c.parentId !== null)
        .forEach((child: Category) => {
          const parentExists = parents.some(
            (p: Category) => p.id === child.parentId
          );
          if (parentExists) {
            if (!children[child.parentId!]) {
              children[child.parentId!] = [];
            }
            children[child.parentId!].push(child);
          } else {
            orphans.push(child);
          }
        });

      return {
        parentCategories: parents,
        childrenByParent: children,
        orphanCategories: orphans,
      };
    }, [metadata?.categories]);

  // Initialiser tous les parents selon la préférence sauvegardée
  useEffect(() => {
    if (parentCategories.length > 0 && expandedParents.size === 0) {
      if (expandAllByDefault) {
        setExpandedParents(
          new Set(parentCategories.map((p: Category) => p.id))
        );
      } else {
        setExpandedParents(new Set());
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [parentCategories.length, expandAllByDefault]);

  const refresh = useCallback(() => {
    invalidateAllCategoryQueries(queryClient);
  }, [queryClient]);

  const getCategoryStats = useCallback(
    (categoryId: string, includeChildren = false) => {
      if (!categoryStats) return { total: 0, count: 0 };

      let categoryIds = [categoryId];

      if (includeChildren && childrenByParent[categoryId]) {
        categoryIds = [
          ...categoryIds,
          ...childrenByParent[categoryId].map((c) => c.id),
        ];
      }

      // Sum stats from all category IDs
      let total = 0;
      let count = 0;

      categoryIds.forEach((id) => {
        const stats = categoryStats[id];
        if (stats) {
          total += stats.total;
          count += stats.count;
        }
      });

      return { total, count };
    },
    [categoryStats, childrenByParent]
  );

  if (isLoadingMetadata || !metadata || isLoadingStats || !categoryStats) {
    return <LoadingState />;
  }

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

  const toggleExpanded = (parentId: string) => {
    const newExpanded = new Set(expandedParents);
    if (newExpanded.has(parentId)) {
      newExpanded.delete(parentId);
    } else {
      newExpanded.add(parentId);
    }
    setExpandedParents(newExpanded);
  };

  const expandAll = () => {
    setExpandedParents(new Set(parentCategories.map((p: Category) => p.id)));
    setExpandAllByDefault(true);
  };

  const collapseAll = () => {
    setExpandedParents(new Set());
    setExpandAllByDefault(false);
  };

  const allExpanded =
    parentCategories.length > 0 &&
    expandedParents.size === parentCategories.length;

  const handleNewCategory = (parentId: string | null = null) => {
    setEditingCategory(null);
    setFormData({
      name: "",
      color: "#22c55e",
      icon: "tag",
      keywords: [],
      parentId,
    });
    setIsDialogOpen(true);
  };

  const handleEdit = (category: Category) => {
    setEditingCategory(category);
    setFormData({
      name: category.name,
      color: category.color,
      icon: category.icon,
      keywords: [...category.keywords],
      parentId: category.parentId,
    });
    setIsDialogOpen(true);
  };

  const handleSave = async () => {
    try {
      if (editingCategory) {
        await updateCategory({
          ...editingCategory,
          name: formData.name,
          color: formData.color,
          icon: formData.icon,
          keywords: formData.keywords,
          parentId: formData.parentId,
        });
      } else {
        await addCategory({
          name: formData.name,
          color: formData.color,
          icon: formData.icon,
          keywords: formData.keywords,
          parentId: formData.parentId,
        });
      }
      refresh();
      setIsDialogOpen(false);
    } catch (error) {
      console.error("Error saving category:", error);
      alert("Erreur lors de la sauvegarde de la catégorie");
    }
  };

  const handleDelete = async (categoryId: string) => {
    const hasChildren = childrenByParent[categoryId]?.length > 0;
    const message = hasChildren
      ? "Cette catégorie a des sous-catégories. Supprimer quand même ?"
      : "Supprimer cette catégorie ?";

    if (!confirm(message)) return;

    try {
      await deleteCategory(categoryId);
      refresh();
    } catch (error) {
      console.error("Error deleting category:", error);
      alert("Erreur lors de la suppression de la catégorie");
    }
  };

  const reApplyAutoCategories = async () => {
    setIsRecategorizing(true);
    const results: RecategorizationResult[] = [];

    try {
      // Fetch uncategorized transactions
      const uncategorizedResponse = await fetch(
        "/api/banking/transactions?limit=1000&offset=0&includeUncategorized=true"
      );
      if (!uncategorizedResponse.ok) {
        throw new Error("Failed to fetch uncategorized transactions");
      }
      const { transactions: uncategorized } =
        await uncategorizedResponse.json();

      const { updateTransaction } = await import("@/lib/store-db");

      for (const transaction of uncategorized) {
        const categoryId = autoCategorize(
          transaction.description + " " + (transaction.memo || ""),
          metadata.categories
        );
        if (categoryId) {
          const category = metadata.categories.find(
            (c: Category) => c.id === categoryId
          );
          if (category) {
            results.push({ transaction, category });
            await updateTransaction({ ...transaction, categoryId });
          }
        }
      }

      setRecatResults(results);
      setIsRecatDialogOpen(true);
      refresh();
    } catch (error) {
      console.error("Error re-categorizing:", error);
      alert("Erreur lors de la recatégorisation");
    } finally {
      setIsRecategorizing(false);
    }
  };

  const uncategorizedCount = categoryStats["uncategorized"]?.count || 0;

  // Filtrer les catégories selon la recherche
  const filteredParentCategories = parentCategories.filter(
    (parent: Category) => {
      if (!searchQuery.trim()) return true;
      const query = searchQuery.toLowerCase();
      if (parent.name.toLowerCase().includes(query)) return true;
      if (parent.keywords.some((k: string) => k.toLowerCase().includes(query)))
        return true;
      const children = childrenByParent[parent.id] || [];
      return children.some(
        (c) =>
          c.name.toLowerCase().includes(query) ||
          c.keywords.some((k) => k.toLowerCase().includes(query))
      );
    }
  );

  return (
    <PageLayout>
      <PageHeader
        title="Catégories"
        description={`${parentCategories.length} catégories principales • ${metadata.categories.length - parentCategories.length} sous-catégories`}
        actions={
          <>
            {uncategorizedCount > 0 && (
              <Button
                variant="outline"
                onClick={reApplyAutoCategories}
                disabled={isRecategorizing}
              >
                {isRecategorizing ? (
                  <RefreshCw className="w-4 h-4 mr-2 animate-spin" />
                ) : null}
                Recatégoriser ({uncategorizedCount})
              </Button>
            )}
            <Button onClick={() => handleNewCategory(null)}>
              <Plus className="w-4 h-4 mr-2" />
              Nouvelle catégorie
            </Button>
          </>
        }
      />

      <CategorySearchBar
        searchQuery={searchQuery}
        onSearchChange={setSearchQuery}
        allExpanded={allExpanded}
        onToggleAll={allExpanded ? collapseAll : expandAll}
      />

      <div className="space-y-3 md:space-y-4">
        {filteredParentCategories.map((parent: Category) => {
          const allChildren = childrenByParent[parent.id] || [];
          const children = searchQuery.trim()
            ? allChildren.filter(
                (c) =>
                  c.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
                  c.keywords.some((k) =>
                    k.toLowerCase().includes(searchQuery.toLowerCase())
                  ) ||
                  parent.name.toLowerCase().includes(searchQuery.toLowerCase())
              )
            : allChildren;
          const stats = getCategoryStats(parent.id, true);
          const isExpanded =
            expandedParents.has(parent.id) ||
            (searchQuery.trim() !== "" && children.length > 0);

          return (
            <ParentCategoryRow
              key={parent.id}
              parent={parent}
              children={children}
              stats={stats}
              isExpanded={isExpanded}
              onToggleExpanded={() => toggleExpanded(parent.id)}
              formatCurrency={formatCurrency}
              getCategoryStats={(id) => getCategoryStats(id)}
              onEdit={handleEdit}
              onDelete={handleDelete}
              onNewCategory={handleNewCategory}
            />
          );
        })}

        {orphanCategories.length > 0 && (
          <Card className="card-hover">
            <div className="px-3 py-2 border-b border-border">
              <span className="text-sm font-medium text-muted-foreground">
                Catégories non classées ({orphanCategories.length})
              </span>
            </div>
            <div className="p-2 space-y-1">
              {orphanCategories.map((category) => (
                <CategoryCard
                  key={category.id}
                  category={category}
                  stats={getCategoryStats(category.id)}
                  formatCurrency={formatCurrency}
                  onEdit={handleEdit}
                  onDelete={handleDelete}
                />
              ))}
            </div>
          </Card>
        )}
      </div>

      <CategoryEditDialog
        open={isDialogOpen}
        onOpenChange={setIsDialogOpen}
        editingCategory={editingCategory}
        formData={formData}
        onFormDataChange={setFormData}
        parentCategories={parentCategories}
        onSave={handleSave}
      />

      {/* Dialog des résultats de recatégorisation */}
      <Dialog open={isRecatDialogOpen} onOpenChange={setIsRecatDialogOpen}>
        <DialogContent className="sm:max-w-lg max-h-[80vh] overflow-hidden flex flex-col">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2">
              <CheckCircle2 className="h-5 w-5 text-success" />
              Recatégorisation terminée
            </DialogTitle>
            <DialogDescription>
              {recatResults.length === 0
                ? "Aucune transaction n'a pu être catégorisée automatiquement."
                : `${recatResults.length} transaction${recatResults.length > 1 ? "s" : ""} catégorisée${recatResults.length > 1 ? "s" : ""}`}
            </DialogDescription>
          </DialogHeader>

          {recatResults.length > 0 && (
            <div className="flex-1 overflow-y-auto -mx-6 px-6">
              <div className="space-y-2">
                {recatResults.map((result, index) => (
                  <div
                    key={index}
                    className="flex items-center gap-3 p-2 rounded-lg bg-muted/50 text-sm"
                  >
                    <div className="flex-1 min-w-0">
                      <p className="font-medium truncate">
                        {result.transaction.description}
                      </p>
                      <p className="text-xs text-muted-foreground truncate">
                        {new Date(result.transaction.date).toLocaleDateString(
                          "fr-FR"
                        )}
                        {" • "}
                        {new Intl.NumberFormat("fr-FR", {
                          style: "currency",
                          currency: "EUR",
                        }).format(result.transaction.amount)}
                      </p>
                    </div>
                    <ArrowRight className="h-4 w-4 text-muted-foreground shrink-0" />
                    <Badge
                      variant="secondary"
                      className="gap-1 shrink-0"
                      style={{
                        backgroundColor: `${result.category.color}20`,
                        color: result.category.color,
                      }}
                    >
                      <CategoryIcon
                        icon={result.category.icon}
                        color={result.category.color}
                        size={12}
                      />
                      {result.category.name}
                    </Badge>
                  </div>
                ))}
              </div>
            </div>
          )}

          <div className="flex justify-end pt-4 border-t">
            <Button onClick={() => setIsRecatDialogOpen(false)}>Fermer</Button>
          </div>
        </DialogContent>
      </Dialog>
    </PageLayout>
  );
}
