"use client";

import { useState, useMemo, useEffect } from "react";
import Link from "next/link";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { CategoryIcon } from "@/components/ui/category-icon";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import { Button } from "@/components/ui/button";
import { useIsMobile } from "@/hooks/use-mobile";
import {
  BarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
} from "recharts";
import { List, ListOrdered } from "lucide-react";
import type { Transaction, Category } from "@/lib/types";

interface TopExpensesListProps {
  expensesByCategory: Array<{
    categoryId: string | null;
    expenses: Transaction[];
  }>;
  categories: Category[];
  formatCurrency: (amount: number) => string;
  allTransactions?: Transaction[]; // Toutes les transactions filtrées pour calculer toutes les dépenses
}

export function TopExpensesList({
  expensesByCategory,
  categories,
  formatCurrency,
  allTransactions = [],
}: TopExpensesListProps) {
  const isMobile = useIsMobile();
  const [showAllExpenses, setShowAllExpenses] = useState(false);

  // Filtrer les catégories qui ont des dépenses
  const categoriesWithExpenses = expensesByCategory.filter(
    (group) => group.expenses.length > 0,
  );

  const hasExpenses = categoriesWithExpenses.length > 0;

  // Déterminer la valeur par défaut du premier onglet
  const defaultTabValue =
    categoriesWithExpenses.length > 0
      ? categoriesWithExpenses[0].categoryId || "uncategorized"
      : "";

  const [activeTab, setActiveTab] = useState<string>(() => defaultTabValue);

  // Mettre à jour activeTab quand defaultTabValue change ou si activeTab est invalide
  useEffect(() => {
    if (!defaultTabValue) return;
    
    // Vérifier si activeTab correspond à une catégorie valide
    const isValidTab = categoriesWithExpenses.some(
      (group) => (group.categoryId || "uncategorized") === activeTab,
    );
    
    // Si activeTab est vide ou invalide, utiliser defaultTabValue
    if (!activeTab || !isValidTab) {
      setActiveTab(defaultTabValue);
    }
  }, [defaultTabValue, categoriesWithExpenses, activeTab]);

  // Calculer les données du graphique pour la catégorie active
  const chartData = useMemo(() => {
    if (!hasExpenses) return [];

    // Utiliser activeTab ou defaultTabValue comme fallback
    const currentTab = activeTab || defaultTabValue;
    if (!currentTab) return [];

    const activeCategoryGroup = categoriesWithExpenses.find(
      (group) => (group.categoryId || "uncategorized") === currentTab,
    );

    if (!activeCategoryGroup) {
      return [];
    }

    // Si showAllExpenses est activé et qu'on a toutes les transactions, utiliser toutes les dépenses de la catégorie
    let expenses: Transaction[];
    if (showAllExpenses && allTransactions.length > 0) {
      // Filtrer toutes les transactions pour obtenir toutes les dépenses de cette catégorie parente
      const categoryId = activeCategoryGroup.categoryId;
      expenses = allTransactions
        .filter((t) => t.amount < 0) // Seulement les dépenses
        .filter((t) => {
          if (categoryId === null) {
            return !t.categoryId;
          }
          // Vérifier si la transaction appartient à cette catégorie parente ou ses sous-catégories
          const category = categories.find((c) => c.id === t.categoryId);
          if (!category) {
            return false;
          }
          const transactionGroupId = category.parentId || category.id;
          return transactionGroupId === categoryId;
        });
    } else {
      // Utiliser seulement les top 10
      expenses = activeCategoryGroup.expenses;
    }

    if (expenses.length === 0) {
      return [];
    }

    // Grouper les dépenses par période
    // Si moins de 30 jours, groupe par jour
    // Si moins de 6 mois, groupe par semaine
    // Sinon groupe par mois
    const sortedExpenses = [...expenses].sort(
      (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
    );

    if (sortedExpenses.length === 0) return [];

    const firstDate = new Date(sortedExpenses[0].date);
    const lastDate = new Date(
      sortedExpenses[sortedExpenses.length - 1].date,
    );
    const daysDiff =
      (lastDate.getTime() - firstDate.getTime()) / (1000 * 60 * 60 * 24);

    let groupBy: "day" | "week" | "month";
    if (daysDiff <= 30) {
      groupBy = "day";
    } else if (daysDiff <= 180) {
      groupBy = "week";
    } else {
      groupBy = "month";
    }

    // Fonction helper pour obtenir la clé de période d'une date
    const getPeriodKey = (date: Date): { key: string; dateKey: string } => {
      if (groupBy === "day") {
        return {
          key: date.toLocaleDateString("fr-FR", {
            day: "2-digit",
            month: "short",
          }),
          dateKey: date.toISOString().substring(0, 10), // YYYY-MM-DD
        };
      } else if (groupBy === "week") {
        // Semaine commençant le lundi
        const weekStart = new Date(date);
        const day = weekStart.getDay();
        const diff = weekStart.getDate() - day + (day === 0 ? -6 : 1);
        weekStart.setDate(diff);
        return {
          key: `Sem. ${weekStart.toLocaleDateString("fr-FR", {
            day: "2-digit",
            month: "short",
          })}`,
          dateKey: weekStart.toISOString().substring(0, 10), // YYYY-MM-DD
        };
      } else {
        return {
          key: date.toLocaleDateString("fr-FR", {
            month: "short",
            year: "numeric",
          }),
          dateKey: `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`, // YYYY-MM
        };
      }
    };

    // Grouper les dépenses par période
    const groupedData = new Map<
      string,
      { total: number; dateKey: string }
    >();

    sortedExpenses.forEach((expense) => {
      const date = new Date(expense.date);
      const { key, dateKey } = getPeriodKey(date);

      const current = groupedData.get(key);
      if (current) {
        current.total += Math.abs(expense.amount);
      } else {
        groupedData.set(key, {
          total: Math.abs(expense.amount),
          dateKey,
        });
      }
    });

    // Générer toutes les périodes entre la première et la dernière date
    const allPeriodsMap = new Map<
      string,
      { period: string; montant: number; dateKey: string }
    >();
    const currentDate = new Date(firstDate);
    const endDate = new Date(lastDate);

    // Normaliser les dates selon le type de groupement
    if (groupBy === "day") {
      currentDate.setHours(0, 0, 0, 0);
      endDate.setHours(23, 59, 59, 999);
    } else if (groupBy === "week") {
      // Début de la semaine de la première date
      const day = currentDate.getDay();
      const diff = currentDate.getDate() - day + (day === 0 ? -6 : 1);
      currentDate.setDate(diff);
      currentDate.setHours(0, 0, 0, 0);
      // Début de la semaine de la dernière date (pour la boucle)
      const lastDay = endDate.getDay();
      const lastDiff = endDate.getDate() - lastDay + (lastDay === 0 ? -6 : 1);
      endDate.setDate(lastDiff);
      endDate.setHours(0, 0, 0, 0);
    } else {
      // Mois : premier jour du mois
      currentDate.setDate(1);
      currentDate.setHours(0, 0, 0, 0);
      endDate.setDate(1);
      endDate.setHours(0, 0, 0, 0);
    }

    while (currentDate <= endDate) {
      const { key, dateKey } = getPeriodKey(currentDate);
      const existingData = groupedData.get(key);

      // Utiliser dateKey comme clé unique pour éviter les doublons
      if (!allPeriodsMap.has(dateKey)) {
        allPeriodsMap.set(dateKey, {
          period: key,
          montant: existingData ? Math.round(existingData.total) : 0,
          dateKey,
        });
      }

      // Passer à la période suivante
      if (groupBy === "day") {
        currentDate.setDate(currentDate.getDate() + 1);
      } else if (groupBy === "week") {
        currentDate.setDate(currentDate.getDate() + 7);
      } else {
        // Mois suivant
        currentDate.setMonth(currentDate.getMonth() + 1);
      }
    }

    return Array.from(allPeriodsMap.values())      .sort((a, b) =>
      a.dateKey.localeCompare(b.dateKey),
    );
  }, [
    hasExpenses,
    categoriesWithExpenses,
    activeTab,
    defaultTabValue,
    showAllExpenses,
    allTransactions,
    categories,
  ]);

  return (
    <Card className="card-hover">
      <CardHeader>
        <CardTitle className="text-sm md:text-base">
          Top 10 dépenses par top 5 catégories parentes
        </CardTitle>
      </CardHeader>
      <CardContent>
        {hasExpenses ? (
          <Tabs
            defaultValue={defaultTabValue}
            value={activeTab || defaultTabValue}
            onValueChange={setActiveTab}
            className="w-full"
          >
            <TabsList className="w-full flex-wrap h-auto p-1 mb-4">
              {categoriesWithExpenses.map(({ categoryId, expenses }) => {
                const category = categoryId
                  ? categories.find((c) => c.id === categoryId)
                  : null;
                const tabValue = categoryId || "uncategorized";

                return (
                  <TabsTrigger
                    key={tabValue}
                    value={tabValue}
                    className="flex items-center gap-1.5 md:gap-2 text-xs md:text-sm"
                  >
                    {category && (
                      <CategoryIcon
                        icon={category.icon}
                        color={category.color}
                        size={isMobile ? 12 : 14}
                      />
                    )}
                    <span className="truncate max-w-[100px] md:max-w-none">
                      {category?.name || "Non catégorisé"}
                    </span>
                  </TabsTrigger>
                );
              })}
            </TabsList>
            {categoriesWithExpenses.map(({ categoryId, expenses }) => {
              const category = categoryId
                ? categories.find((c) => c.id === categoryId)
                : null;
              const tabValue = categoryId || "uncategorized";

              return (
                <TabsContent key={tabValue} value={tabValue}>
                  <div className="space-y-2 md:space-y-3">
                    {expenses.map((expense, index) => (
                      <div
                        key={expense.id}
                        className="flex items-start gap-2 md:gap-3"
                      >
                        <div className="w-5 h-5 md:w-6 md:h-6 rounded-full bg-muted flex items-center justify-center text-[10px] md:text-xs font-semibold shrink-0">
                          {index + 1}
                        </div>
                        <div className="flex-1 min-w-0">
                          <div className="flex items-start justify-between gap-2 mb-1">
                            <p className="font-medium text-xs md:text-sm truncate flex-1">
                              {expense.description}
                            </p>
                            <div className="text-destructive font-semibold tabular-nums text-xs md:text-sm shrink-0">
                              {formatCurrency(expense.amount)}
                            </div>
                          </div>
                          <div className="flex items-center gap-1.5 md:gap-2 flex-wrap">
                            <span className="text-[10px] md:text-xs text-muted-foreground">
                              {new Date(expense.date).toLocaleDateString(
                                "fr-FR",
                              )}
                            </span>
                            {expense.categoryId &&
                              (() => {
                                const expenseCategory = categories.find(
                                  (c) => c.id === expense.categoryId,
                                );
                                // Afficher seulement si c'est une sous-catégorie (a un parentId)
                                if (expenseCategory?.parentId) {
                                  return (
                                    <Link
                                      href={`/transactions?categoryIds=${expenseCategory.id}`}
                                      className="inline-block"
                                    >
                                      <Badge
                                        variant="secondary"
                                        className="text-[10px] md:text-xs px-1.5 md:px-2 py-0.5 inline-flex items-center gap-1 shrink-0 hover:opacity-80 transition-opacity cursor-pointer"
                                        style={{
                                          backgroundColor: `${expenseCategory.color}20`,
                                          color: expenseCategory.color,
                                          borderColor: `${expenseCategory.color}30`,
                                        }}
                                      >
                                        <CategoryIcon
                                          icon={expenseCategory.icon}
                                          color={expenseCategory.color}
                                          size={isMobile ? 8 : 10}
                                        />
                                        <span className="truncate max-w-[100px] md:max-w-none">
                                          {expenseCategory.name}
                                        </span>
                                      </Badge>
                                    </Link>
                                  );
                                }
                                return null;
                              })()}
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                </TabsContent>
              );
            })}
            {/* Graphique d'évolution temporelle */}
            {chartData.length > 0 && (() => {
              const currentTab = activeTab || defaultTabValue;
              const activeCategoryGroup = categoriesWithExpenses.find(
                (group) => (group.categoryId || "uncategorized") === currentTab,
              );
              const activeCategory = activeCategoryGroup?.categoryId
                ? categories.find((c) => c.id === activeCategoryGroup.categoryId)
                : null;
              const barColor = activeCategory?.color || "var(--destructive)";

              return (
                <div className="mt-6 pt-6 border-t border-border">
                  <div className="flex items-center justify-between mb-4">
                    <h3 className="text-sm font-semibold">
                      Évolution des dépenses dans le temps
                    </h3>
                    {allTransactions.length > 0 && (
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => setShowAllExpenses(!showAllExpenses)}
                        className="text-xs"
                      >
                        {showAllExpenses ? (
                          <>
                            <ListOrdered className="w-3 h-3 mr-1.5" />
                            Top 10 seulement
                          </>
                        ) : (
                          <>
                            <List className="w-3 h-3 mr-1.5" />
                            Voir toutes les dépenses
                          </>
                        )}
                      </Button>
                    )}
                  </div>
                  <div className="h-[250px]">
                    <ResponsiveContainer width="100%" height="100%">
                      <BarChart data={chartData}>
                        <CartesianGrid
                          strokeDasharray="3 3"
                          className="stroke-muted"
                        />
                        <XAxis
                          dataKey="period"
                          className="text-xs"
                          interval="preserveStartEnd"
                          angle={-45}
                          textAnchor="end"
                          height={60}
                        />
                        <YAxis
                          className="text-xs"
                          width={80}
                          tickFormatter={(v) => {
                            if (Math.abs(v) >= 1000) {
                              return `${(v / 1000).toFixed(1)}k€`;
                            }
                            return `${Math.round(v)}€`;
                          }}
                          tick={{ fill: "var(--muted-foreground)" }}
                        />
                        <Tooltip
                          formatter={(value: number) => formatCurrency(value)}
                          contentStyle={{
                            backgroundColor: "var(--card)",
                            border: "1px solid var(--border)",
                            borderRadius: "8px",
                          }}
                        />
                        <Bar
                          dataKey="montant"
                          fill={barColor}
                          radius={[4, 4, 0, 0]}
                        />
                      </BarChart>
                    </ResponsiveContainer>
                  </div>
                </div>
              );
            })()}
          </Tabs>
        ) : (
          <div className="h-[200px] flex items-center justify-center text-muted-foreground text-xs md:text-sm">
            Pas de dépenses pour cette période
          </div>
        )}
      </CardContent>
    </Card>
  );
}
