'use client';

import { useCallback, useMemo } from 'react';

import { useLocalStorage } from '@djangocfg/ui-core/hooks';

import {
  CHAT_SETTINGS_STORAGE_KEY,
  DEFAULT_CHAT_SETTINGS,
  type ChatAudioSettings,
  type ChatDockSettings,
  type ChatPageContextSettings,
  type ChatSettings,
  type ChatSpeechSettings,
} from './types';

/** Options for {@link useChatSettings}. */
export interface UseChatSettingsOptions {
  /**
   * Override the storage key (per-product scoping). Defaults to the
   * shared {@link CHAT_SETTINGS_STORAGE_KEY}.
   */
  storageKey?: string;
  /**
   * Override baseline defaults — merged over {@link DEFAULT_CHAT_SETTINGS}
   * at the slice level (per-product branding, host opt-ins, etc.).
   */
  defaults?: Partial<ChatSettings>;
}

/** Everything {@link useChatSettings} exposes. */
export interface UseChatSettingsReturn {
  /** The full, typed settings object (each slice always present). */
  settings: ChatSettings;

  /**
   * Top-level grouped patch — shallow-merges whole slices. Use this for
   * cross-slice updates; for a single slice prefer the typed helpers.
   */
  patch: (partial: Partial<ChatSettings>) => void;

  /** Merge a subset of dock fields. */
  updateDock: (partial: Partial<ChatDockSettings>) => void;
  /** Merge a subset of audio fields. */
  updateAudio: (partial: Partial<ChatAudioSettings>) => void;
  /** Merge a subset of speech fields. */
  updateSpeech: (partial: Partial<ChatSpeechSettings>) => void;
  /** Merge a subset of page-context fields. */
  updatePageContext: (partial: Partial<ChatPageContextSettings>) => void;

  /** Master audio mute shortcut. */
  setAudioMuted: (muted: boolean) => void;
  /** Page-context opt-in shortcut. */
  setPageContextLinked: (linked: boolean) => void;

  /** Reset every slice back to defaults. */
  reset: () => void;
}

/** Shallow-merge `defaults` slices over the baseline. */
function resolveDefaults(defaults?: Partial<ChatSettings>): ChatSettings {
  if (!defaults) return DEFAULT_CHAT_SETTINGS;
  return {
    dock: { ...DEFAULT_CHAT_SETTINGS.dock, ...defaults.dock },
    audio: { ...DEFAULT_CHAT_SETTINGS.audio, ...defaults.audio },
    speech: { ...DEFAULT_CHAT_SETTINGS.speech, ...defaults.speech },
    pageContext: {
      ...DEFAULT_CHAT_SETTINGS.pageContext,
      ...defaults.pageContext,
    },
  };
}

/**
 * The single entry point for chat-owned persisted settings.
 *
 * Every chat feature that wants to remember a preference goes through
 * here instead of calling `useLocalStorage` with its own key. Why:
 *
 * - One typed object, one storage key — "the chat's settings" is a single
 *   thing that can be reasoned about, exported, or reset wholesale.
 * - Coalesced writes: `useLocalStorage` (Part 1) updates React state
 *   synchronously but batches the actual `localStorage` write to one per
 *   tick — so several features patching different slices in the same
 *   render commit collapse into a single write, no thrash.
 * - Cross-instance sync: two `useChatSettings()` consumers (e.g. the
 *   header audio toggle and the settings panel) stay in lockstep within
 *   the same tab and across tabs.
 *
 * Each helper updates only its own slice, leaving sibling slices
 * untouched — a feature never has to know about the others.
 *
 * SSR-safe: returns defaults on the server, hydrates on mount.
 */
export function useChatSettings(
  opts: UseChatSettingsOptions = {},
): UseChatSettingsReturn {
  const key = opts.storageKey ?? CHAT_SETTINGS_STORAGE_KEY;
  // Memoized so the resolved defaults keep a stable identity — passing a
  // fresh object to `useLocalStorage` each render is harmless but wasteful.
  const initial = useMemo(
    () => resolveDefaults(opts.defaults),
    [opts.defaults],
  );

  const [settings, setSettings, , patch] = useLocalStorage<ChatSettings>(
    key,
    initial,
  );

  // Slice updaters: read the current slice, shallow-merge the partial,
  // write back via the coalescing top-level `patch`. The inner
  // `useLocalStorage` `patch` already skips no-op writes.
  const updateDock = useCallback(
    (partial: Partial<ChatDockSettings>) => {
      patch({ dock: { ...settings.dock, ...partial } });
    },
    [patch, settings.dock],
  );

  const updateAudio = useCallback(
    (partial: Partial<ChatAudioSettings>) => {
      patch({ audio: { ...settings.audio, ...partial } });
    },
    [patch, settings.audio],
  );

  const updateSpeech = useCallback(
    (partial: Partial<ChatSpeechSettings>) => {
      patch({ speech: { ...settings.speech, ...partial } });
    },
    [patch, settings.speech],
  );

  const updatePageContext = useCallback(
    (partial: Partial<ChatPageContextSettings>) => {
      patch({ pageContext: { ...settings.pageContext, ...partial } });
    },
    [patch, settings.pageContext],
  );

  const setAudioMuted = useCallback(
    (muted: boolean) => updateAudio({ muted }),
    [updateAudio],
  );

  const setPageContextLinked = useCallback(
    (linked: boolean) => updatePageContext({ linked }),
    [updatePageContext],
  );

  const reset = useCallback(
    () => setSettings(initial),
    [setSettings, initial],
  );

  return {
    settings,
    patch,
    updateDock,
    updateAudio,
    updateSpeech,
    updatePageContext,
    setAudioMuted,
    setPageContextLinked,
    reset,
  };
}
