"use client";

import { create } from "zustand";
import { devtools, persist } from "zustand/middleware";
import { clearTabCache } from "@/lib/tabStateCache";

// --- 타입 정의 ---

export type AppMode = "user" | "admin";

export interface Tab {
  id: string;
  type: "screen" | "admin";
  title: string;
  screenId?: number;
  menuObjid?: number;
  adminUrl?: string;
}

interface ModeTabData {
  tabs: Tab[];
  activeTabId: string | null;
}

interface TabState {
  mode: AppMode;
  user: ModeTabData;
  admin: ModeTabData;
  refreshKeys: Record<string, number>;

  setMode: (mode: AppMode) => void;

  openTab: (tab: Omit<Tab, "id">, insertIndex?: number) => void;
  closeTab: (tabId: string) => void;
  switchTab: (tabId: string) => void;
  refreshTab: (tabId: string) => void;

  closeOtherTabs: (tabId: string) => void;
  closeTabsToLeft: (tabId: string) => void;
  closeTabsToRight: (tabId: string) => void;
  closeAllTabs: () => void;

  updateTabOrder: (fromIndex: number, toIndex: number) => void;
}

// --- 헬퍼 함수 ---

function generateTabId(tab: Omit<Tab, "id">): string {
  if (tab.type === "screen" && tab.screenId != null) {
    return `tab-screen-${tab.screenId}-${tab.menuObjid ?? 0}`;
  }
  if (tab.type === "admin" && tab.adminUrl) {
    return `tab-admin-${tab.adminUrl.replace(/[^a-zA-Z0-9]/g, "-")}`;
  }
  return `tab-${Date.now()}`;
}

function findDuplicateTab(tabs: Tab[], newTab: Omit<Tab, "id">): Tab | undefined {
  if (newTab.type === "screen" && newTab.screenId != null) {
    return tabs.find(
      (t) => t.type === "screen" && t.screenId === newTab.screenId && t.menuObjid === newTab.menuObjid,
    );
  }
  if (newTab.type === "admin" && newTab.adminUrl) {
    return tabs.find((t) => t.type === "admin" && t.adminUrl === newTab.adminUrl);
  }
  return undefined;
}

function getNextActiveTabId(tabs: Tab[], closedTabId: string, currentActiveId: string | null): string | null {
  if (currentActiveId !== closedTabId) return currentActiveId;
  const idx = tabs.findIndex((t) => t.id === closedTabId);
  if (idx === -1) return null;
  const remaining = tabs.filter((t) => t.id !== closedTabId);
  if (remaining.length === 0) return null;
  if (idx > 0) return remaining[Math.min(idx - 1, remaining.length - 1)].id;
  return remaining[0].id;
}

// 현재 모드의 데이터 키 반환
function modeKey(state: TabState): AppMode {
  return state.mode;
}

// --- 셀렉터 (컴포넌트에서 사용) ---

export function selectTabs(state: TabState): Tab[] {
  return state[state.mode].tabs;
}

export function selectActiveTabId(state: TabState): string | null {
  return state[state.mode].activeTabId;
}

// --- Store ---

const EMPTY_MODE: ModeTabData = { tabs: [], activeTabId: null };

export const useTabStore = create<TabState>()(
  devtools(
    persist(
      (set, get) => ({
        mode: "user" as AppMode,
        user: { ...EMPTY_MODE },
        admin: { ...EMPTY_MODE },
        refreshKeys: {},

        setMode: (mode) => {
          set({ mode });
        },

        openTab: (tabData, insertIndex) => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          const existing = findDuplicateTab(modeData.tabs, tabData);

          if (existing) {
            set({ [mk]: { ...modeData, activeTabId: existing.id } });
            return;
          }

          const id = generateTabId(tabData);
          const newTab: Tab = { ...tabData, id };
          const newTabs = [...modeData.tabs];

          if (insertIndex != null && insertIndex >= 0 && insertIndex <= newTabs.length) {
            newTabs.splice(insertIndex, 0, newTab);
          } else {
            newTabs.push(newTab);
          }

          set({ [mk]: { tabs: newTabs, activeTabId: id } });
        },

        closeTab: (tabId) => {
          clearTabCache(tabId);
          const mk = modeKey(get());
          const modeData = get()[mk];
          const nextActive = getNextActiveTabId(modeData.tabs, tabId, modeData.activeTabId);
          const newTabs = modeData.tabs.filter((t) => t.id !== tabId);
          const { [tabId]: _, ...restKeys } = get().refreshKeys;
          set({ [mk]: { tabs: newTabs, activeTabId: nextActive }, refreshKeys: restKeys });
        },

        switchTab: (tabId) => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          set({ [mk]: { ...modeData, activeTabId: tabId } });
        },

        refreshTab: (tabId) => {
          clearTabCache(tabId);
          set((state) => ({
            refreshKeys: { ...state.refreshKeys, [tabId]: (state.refreshKeys[tabId] || 0) + 1 },
          }));
        },

        closeOtherTabs: (tabId) => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          modeData.tabs.filter((t) => t.id !== tabId).forEach((t) => clearTabCache(t.id));
          set({ [mk]: { tabs: modeData.tabs.filter((t) => t.id === tabId), activeTabId: tabId } });
        },

        closeTabsToLeft: (tabId) => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          const idx = modeData.tabs.findIndex((t) => t.id === tabId);
          if (idx === -1) return;
          modeData.tabs.slice(0, idx).forEach((t) => clearTabCache(t.id));
          set({ [mk]: { tabs: modeData.tabs.slice(idx), activeTabId: tabId } });
        },

        closeTabsToRight: (tabId) => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          const idx = modeData.tabs.findIndex((t) => t.id === tabId);
          if (idx === -1) return;
          modeData.tabs.slice(idx + 1).forEach((t) => clearTabCache(t.id));
          set({ [mk]: { tabs: modeData.tabs.slice(0, idx + 1), activeTabId: tabId } });
        },

        closeAllTabs: () => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          modeData.tabs.forEach((t) => clearTabCache(t.id));
          set({ [mk]: { tabs: [], activeTabId: null } });
        },

        updateTabOrder: (fromIndex, toIndex) => {
          const mk = modeKey(get());
          const modeData = get()[mk];
          const newTabs = [...modeData.tabs];
          const [moved] = newTabs.splice(fromIndex, 1);
          newTabs.splice(toIndex, 0, moved);
          set({ [mk]: { ...modeData, tabs: newTabs } });
        },
      }),
      {
        name: "erp-tab-store",
        storage: {
          getItem: (name) => {
            if (typeof window === "undefined") return null;
            const raw = sessionStorage.getItem(name);
            return raw ? JSON.parse(raw) : null;
          },
          setItem: (name, value) => {
            if (typeof window === "undefined") return;
            sessionStorage.setItem(name, JSON.stringify(value));
          },
          removeItem: (name) => {
            if (typeof window === "undefined") return;
            sessionStorage.removeItem(name);
          },
        },
        partialize: (state) => ({
          mode: state.mode,
          user: state.user,
          admin: state.admin,
        }) as unknown as TabState,
      },
    ),
    { name: "TabStore" },
  ),
);
