import { ReactNode, useCallback, useMemo, useState } from 'react';
import { createContext, useContextSelector } from 'use-context-selector';
import {
  getRestNonce,
  IS_WORDPRESS,
  PLUGIN_ASSISTANT_SETTINGS,
  PLUGIN_REST_ENDPOINTS,
  syncPluginAssistantSettings,
} from '../constants';

export type PluginSettingsState = {
  allowActionPanelAiRequests: boolean;
  allowLogReads: boolean;
  allowWriteOperations: boolean;
  autoApproveSafeWriteOperations: boolean;
  requireReadApproval: boolean;
  setupCompleted: boolean;
};

type PluginSettingsPatch = Partial<PluginSettingsState>;

interface PluginSettingsContextProps {
  settings: PluginSettingsState;
  isSaving: boolean;
  error: string | null;
  updateSettings: (patch: PluginSettingsPatch) => Promise<PluginSettingsState>;
}

const defaultSettings: PluginSettingsState = {
  allowActionPanelAiRequests: Boolean(
    PLUGIN_ASSISTANT_SETTINGS.allowActionPanelAiRequests ?? PLUGIN_ASSISTANT_SETTINGS.assistantEnabled
  ),
  allowLogReads: Boolean(PLUGIN_ASSISTANT_SETTINGS.allowLogReads),
  allowWriteOperations: Boolean(PLUGIN_ASSISTANT_SETTINGS.allowWriteOperations),
  autoApproveSafeWriteOperations: PLUGIN_ASSISTANT_SETTINGS.autoApproveSafeWriteOperations ?? true,
  requireReadApproval: Boolean(PLUGIN_ASSISTANT_SETTINGS.requireReadApproval),
  setupCompleted: PLUGIN_ASSISTANT_SETTINGS.setupCompleted ?? true,
};

const PluginSettingsContext = createContext<PluginSettingsContextProps>({
  settings: defaultSettings,
  isSaving: false,
  error: null,
  updateSettings: async () => defaultSettings,
});

const coerceSettings = (value: unknown, fallback: PluginSettingsState): PluginSettingsState => {
  const source = value && typeof value === 'object' ? value as Record<string, unknown> : {};
  return {
    allowActionPanelAiRequests: Boolean(
      source.allowActionPanelAiRequests ?? source.assistantEnabled ?? fallback.allowActionPanelAiRequests
    ),
    allowLogReads: Boolean(source.allowLogReads ?? fallback.allowLogReads),
    allowWriteOperations: Boolean(source.allowWriteOperations ?? fallback.allowWriteOperations),
    autoApproveSafeWriteOperations: Boolean(
      source.autoApproveSafeWriteOperations ?? fallback.autoApproveSafeWriteOperations
    ),
    requireReadApproval: Boolean(source.requireReadApproval ?? fallback.requireReadApproval),
    setupCompleted: Boolean(source.setupCompleted ?? fallback.setupCompleted),
  };
};

export function PluginSettingsProvider({ children }: { children: ReactNode }) {
  const [settings, setSettings] = useState(defaultSettings);
  const [isSaving, setIsSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const updateSettings = useCallback(async (patch: PluginSettingsPatch) => {
    if (!IS_WORDPRESS) {
      const nextSettings = { ...settings, ...patch };
      setSettings(nextSettings);
      syncPluginAssistantSettings(nextSettings);
      return nextSettings;
    }

    setIsSaving(true);
    setError(null);
    try {
      const response = await fetch(PLUGIN_REST_ENDPOINTS.settings, {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': getRestNonce() },
        body: JSON.stringify(patch),
      });
      const payload = await response.json().catch(() => ({}));
      const returnedSettings = coerceSettings(payload?.settings, settings);
      setSettings(returnedSettings);
      syncPluginAssistantSettings(returnedSettings);
      if (!response.ok) {
        throw new Error(payload?.message || 'Failed to update plugin settings.');
      }
      return returnedSettings;
    } catch (e) {
      const message = e instanceof Error ? e.message : 'Failed to update plugin settings.';
      setError(message);
      throw e;
    } finally {
      setIsSaving(false);
    }
  }, [settings]);

  const value = useMemo(() => ({
    settings,
    isSaving,
    error,
    updateSettings,
  }), [settings, isSaving, error, updateSettings]);

  return (
    <PluginSettingsContext.Provider value={value}>
      {children}
    </PluginSettingsContext.Provider>
  );
}

const usePluginSettingsSelector = <T,>(selector: (state: PluginSettingsContextProps) => T): T => (
  useContextSelector(PluginSettingsContext, selector)
);

export const usePluginSettings = () => usePluginSettingsSelector(state => state.settings);
export const usePluginSettingsSaving = () => usePluginSettingsSelector(state => state.isSaving);
export const usePluginSettingsError = () => usePluginSettingsSelector(state => state.error);
export const useUpdatePluginSettings = () => usePluginSettingsSelector(state => state.updateSettings);
