import { useCallback, useState } from 'react';

// Persisted UI state for the shell sidebar (issue #396). Two client-local preferences,
// namespaced `ctv-*` per the persisted-UI-state convention (spa-conventions.md §5d):
//   - ctv-sidebar-collapsed: "1" | "0" — is the sidebar collapsed to the icon rail?
//   - ctv-sidebar-groups:   JSON {groupKey: boolean} — is a labeled nav group collapsed?
// A labeled group with no stored entry defaults to COLLAPSED, so a fresh load shows only the
// always-open Primary group. (The prototype named these keys `ctv.sidebar.*`; we use the
// established `ctv-` hyphen form — see docs/decisions.md 2026-07-18.)

const COLLAPSED_KEY = 'ctv-sidebar-collapsed';
const GROUPS_KEY = 'ctv-sidebar-groups';

function getStorage(): Storage | null {
  try {
    return window.localStorage;
  } catch {
    // Storage can be disabled/unavailable (privacy mode, sandboxed iframe) — degrade to defaults.
    return null;
  }
}

export function getStoredSidebarCollapsed(): boolean {
  return getStorage()?.getItem(COLLAPSED_KEY) === '1';
}

function setStoredSidebarCollapsed(collapsed: boolean): void {
  try {
    getStorage()?.setItem(COLLAPSED_KEY, collapsed ? '1' : '0');
  } catch {
    // ignore write failures (quota / unavailable) — in-memory state still updates
  }
}

export function getStoredSidebarGroups(): Record<string, boolean> {
  const raw = getStorage()?.getItem(GROUPS_KEY);
  if (!raw) {
    return {};
  }

  try {
    const parsed: unknown = JSON.parse(raw);
    if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
      const out: Record<string, boolean> = {};
      for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
        if (typeof value === 'boolean') {
          out[key] = value;
        }
      }
      return out;
    }
  } catch {
    // malformed JSON — fall through to defaults
  }

  return {};
}

function setStoredSidebarGroups(groups: Record<string, boolean>): void {
  try {
    getStorage()?.setItem(GROUPS_KEY, JSON.stringify(groups));
  } catch {
    // ignore write failures — in-memory state still updates
  }
}

export interface SidebarState {
  /** Is the sidebar collapsed to the icon rail? */
  collapsed: boolean;
  toggleCollapsed: () => void;
  /** Is a labeled nav group collapsed? Unknown groups default to collapsed. */
  isGroupCollapsed: (groupKey: string) => boolean;
  toggleGroup: (groupKey: string) => void;
}

export function useSidebarState(): SidebarState {
  const [collapsed, setCollapsed] = useState<boolean>(getStoredSidebarCollapsed);
  const [groups, setGroups] = useState<Record<string, boolean>>(getStoredSidebarGroups);

  const toggleCollapsed = useCallback(() => {
    setCollapsed((previous) => {
      const next = !previous;
      setStoredSidebarCollapsed(next);
      return next;
    });
  }, []);

  const isGroupCollapsed = useCallback(
    // Absent entry ⇒ default collapsed for labeled groups.
    (groupKey: string) => groups[groupKey] ?? true,
    [groups]
  );

  const toggleGroup = useCallback((groupKey: string) => {
    setGroups((previous) => {
      const currentlyCollapsed = previous[groupKey] ?? true;
      const next = { ...previous, [groupKey]: !currentlyCollapsed };
      setStoredSidebarGroups(next);
      return next;
    });
  }, []);

  return { collapsed, toggleCollapsed, isGroupCollapsed, toggleGroup };
}
