'use client';

import type React from 'react';
import { useState, useCallback, useRef } from 'react';
import { nanoid } from 'nanoid';
import { TableType, type ModeType } from '@/shared/types/common';

export interface TabItem<T> {
  id: string;
  title: string;
  content: T | 'list';
  originalContent?: T;
  closeable?: boolean;
  mode?: ModeType;
  hasUnsavedChanges?: boolean;
  replaceCurrentTab?: boolean;
}

export interface TabConfig<T> {
  type: string;
  listTitle: string;
  newItemTitle: string;
  initialData: T;
  getItemCode: (item: T) => string;
}

export function useTabsManager<T extends { id: string }>(config: TabConfig<T>) {
  const [tabs, setTabs] = useState<TabItem<T>[]>([
    { id: 'list', title: config.listTitle, content: 'list', closeable: false }
  ]);
  const [activeTab, setActiveTab] = useState<string>('list');
  const [showConfirmDialog, setShowConfirmDialog] = useState(false);
  const pendingAction = useRef<'close' | 'cancel' | null>(null);
  const tabToCloseRef = useRef<string | null>(null);

  const findViewTab = useCallback(
    (itemId: string) => {
      return tabs.find((tab) => tab.id === `${itemId}view` && tab.mode === 'view');
    },
    [tabs]
  );

  const checkUnsavedChanges = useCallback((tab: TabItem<T>) => {
    if (tab.content === 'list' || tab.mode === 'view') return false;

    if (!tab.originalContent) return false;

    return JSON.stringify(tab.originalContent) !== JSON.stringify(tab.content);
  }, []);

  const updateTabContent = useCallback((tabId: string, newContent: T) => {
    setTabs((prevTabs) => {
      return prevTabs.map((tab) => {
        if (tab.id === tabId) {
          const updatedTab = { ...tab, content: newContent };
          const hasChanges = tab.originalContent
            ? JSON.stringify(tab.originalContent) !== JSON.stringify(newContent)
            : false;

          updatedTab.hasUnsavedChanges = hasChanges;
          return updatedTab;
        }
        return tab;
      });
    });
  }, []);

  const setTabHasUnsavedChanges = useCallback((tabId: string, hasChanges: boolean) => {
    setTabs((prevTabs) => {
      const tab = prevTabs.find((t) => t.id === tabId);
      if (tab && tab.hasUnsavedChanges === hasChanges) {
        return prevTabs;
      }
      return prevTabs.map((tab) =>
        tab.id === tabId ? { ...tab, hasUnsavedChanges: hasChanges } : tab
      );
    });
  }, []);

  const handleTabClose = useCallback(
    (event: React.MouseEvent, tabId: string) => {
      event.stopPropagation();

      const tabToClose = tabs.find((tab) => tab.id === tabId);
      if (tabToClose?.hasUnsavedChanges) {
        tabToCloseRef.current = tabId;
        pendingAction.current = 'close';
        setShowConfirmDialog(true);
        return;
      }

      setTabs((prevTabs) => prevTabs.filter((tab) => tab.id !== tabId));
      if (activeTab === tabId) {
        setActiveTab('list');
      }
    },
    [activeTab, tabs]
  );

  const handleTabChange = useCallback((event: React.SyntheticEvent, newValue: string) => {
    setActiveTab(newValue);
  }, []);

  const handleConfirmDialogAction = useCallback(() => {
    setShowConfirmDialog(false);
    if (pendingAction.current === 'close') {
      const tabIdToClose = tabToCloseRef.current || activeTab;
      setTabs((prevTabs) => prevTabs.filter((tab) => tab.id !== tabIdToClose));

      if (activeTab === tabIdToClose) {
        setActiveTab('list');
      }
    } else if (pendingAction.current === 'cancel') {
      const tabIdToCancel = tabToCloseRef.current || activeTab;
      setTabs((prevTabs) => 
        prevTabs.map((tab) => {
          if (tab.id === tabIdToCancel) {
            return {
              ...tab,
              content: tab.originalContent || tab.content,
              hasUnsavedChanges: false,
              mode: tab.mode === 'edit' ? 'view' : tab.mode
            };
          }
          return tab;
        })
      );
    }

    pendingAction.current = null;
    tabToCloseRef.current = null;
  }, [activeTab]);

  const handleTabAdd = useCallback(() => {
    const initialContent = { ...config.initialData } as T;
    const newTab: TabItem<T> = {
      id: nanoid(),
      title: config.newItemTitle,
      content: initialContent,
      originalContent: initialContent,
      closeable: true,
      mode: 'add',
      hasUnsavedChanges: false,
    };
    setTabs((prevTabs) => [...prevTabs, newTab]);
    setActiveTab(newTab.id);
  }, [config]);

  const handleCopy = useCallback(
    (item: T) => {
      const initialContent = { ...item } as T;
      const newTab: TabItem<T> = {
        id: `${item.id}copy`,
        title: `Copie de ${config.getItemCode(item)}`,
        content: initialContent,
        originalContent: initialContent,
        closeable: true,
        mode: 'copy',
        hasUnsavedChanges: false,
      };
      setTabs((prevTabs) => [...prevTabs, newTab]);
      setActiveTab(newTab.id);
    },
    [config]
  );

  const handleEdit = useCallback(
    (item: T) => {
      const initialContent = { ...item };
      const viewTab = findViewTab(item.id);
      const currentTab = tabs.find(tab => tab.id === activeTab);
      const shouldReplace = currentTab?.replaceCurrentTab;
      
      if (shouldReplace) {
        setTabs((prevTabs) =>
          prevTabs.map((tab) =>
            tab.id === activeTab
              ? {
                  ...tab,
                  id: `${item.id}edit`,
                  title: config.getItemCode(item),
                  mode: 'edit' as const,
                  content: initialContent,
                  originalContent: initialContent,
                  hasUnsavedChanges: false,
                  replaceCurrentTab: false,
                }
              : tab
          )
        );
        setActiveTab(`${item.id}edit`);
      } else {
        if (viewTab) {
          setTabs((prevTabs) =>
            prevTabs.map((tab) =>
              tab.id === viewTab.id
                ? {
                    ...tab,
                    title: config.getItemCode(item),
                    mode: 'edit' as const,
                    content: initialContent,
                    originalContent: initialContent,
                    hasUnsavedChanges: false,
                  }
                : tab
            )
          );
          setActiveTab(viewTab.id);
        } else {
          const existingTab = tabs.find((tab) => tab.id === `${item.id}edit`);
          if (existingTab) {
            setTabs((prevTabs) =>
              prevTabs.map((tab) =>
                tab.id === existingTab.id
                  ? { ...tab, mode: 'edit' as const }
                  : tab
              )
            );
            setActiveTab(existingTab.id);
          } else {
            const newTab: TabItem<T> = {
              id: `${item.id}edit`,
              title: config.getItemCode(item),
              content: initialContent,
              originalContent: initialContent,
              closeable: true,
              mode: 'edit',
              hasUnsavedChanges: false,
            };
            setTabs((prevTabs) => [...prevTabs, newTab]);
            setActiveTab(newTab.id);
          }
        }
      }
    },
    [tabs, config, findViewTab, activeTab]
  );

  const handleView = useCallback(
    (item: T) => {
      const initialContent = { ...item };
      const existingTab = tabs.find((tab) => tab.id === item.id + 'view');
      if (existingTab) {
        setActiveTab(existingTab.id);
      } else {
        const newTab: TabItem<T> = {
          id: item.id + 'view',
          title: config.getItemCode(item),
          content: initialContent,
          originalContent: initialContent,
          closeable: true,
          mode: 'view',
          hasUnsavedChanges: false,
        };
        setTabs((prevTabs) => [...prevTabs, newTab]);
        setActiveTab(newTab.id);
      }
    },
    [tabs, config]
  );

  const handleCancel = useCallback(
    (tabId: string, forceClose : boolean = false) => {
      const tabToClose = tabs.find((tab) => tab.id === tabId);
      if (!forceClose && tabToClose?.hasUnsavedChanges) {
        tabToCloseRef.current = tabId;
        pendingAction.current = (config.type !== TableType.Circuit && config.type !== TableType.Usager && config.type !== TableType.Avenant) ? 'close' : 'cancel';
        setShowConfirmDialog(true);
        return;
      }
      setTabs((prevTabs) => prevTabs.filter((tab) => tab.id !== tabId));
      setActiveTab('list');
    },
    [config.type, tabs]
  );

  const updateListTabTitle = useCallback((newTitle: string) => {
    setTabs((prevTabs) =>
      prevTabs.map((tab) => (tab.id === 'list' ? { ...tab, title: newTitle } : tab))
    );
  }, []);
  
  const markTabAsSaved = useCallback((tabId: string, content: T) => {
    setTabs((prevTabs) =>
      prevTabs.map((tab) => {
        if (tab.id === tabId && tab.content !== 'list') {
          return {
            ...tab,
            content: content,
            originalContent: content,
            mode: 'view',
            hasUnsavedChanges: false,
          };
        }
        return tab;
      })
    );
  }, []);

  const setTabReplaceCurrentTab = useCallback((tabId: string, replaceCurrentTab: boolean) => {
    setTabs((prevTabs) =>
      prevTabs.map((tab) =>
        tab.id === tabId ? { ...tab, replaceCurrentTab } : tab
      )
    );
  }, []);
  const handleTabAddWithContent =  useCallback(
    (content: T) => {
      const initialContent = ({ ...content } as T)
    const newTab: TabItem<T> = {
      id: nanoid(),
      title: config.newItemTitle,
      content: initialContent,
      originalContent: initialContent,
      closeable: true,
      mode: 'add',
      hasUnsavedChanges: false,
    };
    setTabs((prevTabs) => [...prevTabs, newTab]);
    setActiveTab(newTab.id);
  }, [config]);

  return {
    tabs,
    activeTab,
    handleTabClose,
    handleTabChange,
    handleTabAdd,
    handleEdit,
    handleView,
    handleCancel,
    handleCopy,
    updateListTabTitle,
    setTabHasUnsavedChanges,
    showConfirmDialog,
    setShowConfirmDialog,
    handleConfirmDialogAction,
    updateTabContent,
    checkUnsavedChanges,
    markTabAsSaved,
    setTabReplaceCurrentTab,
    handleTabAddWithContent
  };
}
