/**
 * React Integration fuer @breakpilot/consent-sdk
 *
 * @example
 * ```tsx
 * import { ConsentProvider, useConsent, ConsentBanner } from '@breakpilot/consent-sdk/react';
 *
 * function App() {
 *   return (
 *     <ConsentProvider config={config}>
 *       <ConsentBanner />
 *       <MainContent />
 *     </ConsentProvider>
 *   );
 * }
 * ```
 */

import {
  createContext,
  useContext,
  useEffect,
  useState,
  useCallback,
  useMemo,
  type ReactNode,
  type FC,
} from 'react';
import { ConsentManager } from '../core/ConsentManager';
import type {
  ConsentConfig,
  ConsentState,
  ConsentCategory,
  ConsentCategories,
} from '../types';

// =============================================================================
// Context
// =============================================================================

interface ConsentContextValue {
  /** ConsentManager Instanz */
  manager: ConsentManager | null;

  /** Aktueller Consent-State */
  consent: ConsentState | null;

  /** Ist SDK initialisiert? */
  isInitialized: boolean;

  /** Wird geladen? */
  isLoading: boolean;

  /** Ist Banner sichtbar? */
  isBannerVisible: boolean;

  /** Wird Consent benoetigt? */
  needsConsent: boolean;

  /** Consent fuer Kategorie pruefen */
  hasConsent: (category: ConsentCategory) => boolean;

  /** Alle akzeptieren */
  acceptAll: () => Promise<void>;

  /** Alle ablehnen */
  rejectAll: () => Promise<void>;

  /** Auswahl speichern */
  saveSelection: (categories: Partial<ConsentCategories>) => Promise<void>;

  /** Banner anzeigen */
  showBanner: () => void;

  /** Banner verstecken */
  hideBanner: () => void;

  /** Einstellungen oeffnen */
  showSettings: () => void;
}

const ConsentContext = createContext<ConsentContextValue | null>(null);

// =============================================================================
// Provider
// =============================================================================

interface ConsentProviderProps {
  /** SDK-Konfiguration */
  config: ConsentConfig;

  /** Kinder-Komponenten */
  children: ReactNode;
}

/**
 * ConsentProvider - Stellt Consent-Kontext bereit
 */
export const ConsentProvider: FC<ConsentProviderProps> = ({
  config,
  children,
}) => {
  const [manager, setManager] = useState<ConsentManager | null>(null);
  const [consent, setConsent] = useState<ConsentState | null>(null);
  const [isInitialized, setIsInitialized] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [isBannerVisible, setIsBannerVisible] = useState(false);

  // Manager erstellen und initialisieren
  useEffect(() => {
    const consentManager = new ConsentManager(config);
    setManager(consentManager);

    // Events abonnieren
    const unsubChange = consentManager.on('change', (newConsent) => {
      setConsent(newConsent);
    });

    const unsubBannerShow = consentManager.on('banner_show', () => {
      setIsBannerVisible(true);
    });

    const unsubBannerHide = consentManager.on('banner_hide', () => {
      setIsBannerVisible(false);
    });

    // Initialisieren
    consentManager
      .init()
      .then(() => {
        setConsent(consentManager.getConsent());
        setIsInitialized(true);
        setIsLoading(false);
        setIsBannerVisible(consentManager.isBannerVisible());
      })
      .catch((error) => {
        console.error('Failed to initialize ConsentManager:', error);
        setIsLoading(false);
      });

    // Cleanup
    return () => {
      unsubChange();
      unsubBannerShow();
      unsubBannerHide();
    };
  }, [config]);

  // Callback-Funktionen
  const hasConsent = useCallback(
    (category: ConsentCategory): boolean => {
      return manager?.hasConsent(category) ?? category === 'essential';
    },
    [manager]
  );

  const acceptAll = useCallback(async () => {
    await manager?.acceptAll();
  }, [manager]);

  const rejectAll = useCallback(async () => {
    await manager?.rejectAll();
  }, [manager]);

  const saveSelection = useCallback(
    async (categories: Partial<ConsentCategories>) => {
      await manager?.setConsent(categories);
      manager?.hideBanner();
    },
    [manager]
  );

  const showBanner = useCallback(() => {
    manager?.showBanner();
  }, [manager]);

  const hideBanner = useCallback(() => {
    manager?.hideBanner();
  }, [manager]);

  const showSettings = useCallback(() => {
    manager?.showSettings();
  }, [manager]);

  const needsConsent = useMemo(() => {
    return manager?.needsConsent() ?? true;
  }, [manager, consent]);

  // Context-Wert
  const contextValue = useMemo<ConsentContextValue>(
    () => ({
      manager,
      consent,
      isInitialized,
      isLoading,
      isBannerVisible,
      needsConsent,
      hasConsent,
      acceptAll,
      rejectAll,
      saveSelection,
      showBanner,
      hideBanner,
      showSettings,
    }),
    [
      manager,
      consent,
      isInitialized,
      isLoading,
      isBannerVisible,
      needsConsent,
      hasConsent,
      acceptAll,
      rejectAll,
      saveSelection,
      showBanner,
      hideBanner,
      showSettings,
    ]
  );

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

// =============================================================================
// Hooks
// =============================================================================

/**
 * useConsent - Hook fuer Consent-Zugriff
 *
 * @example
 * ```tsx
 * const { hasConsent, acceptAll, rejectAll } = useConsent();
 *
 * if (hasConsent('analytics')) {
 *   // Analytics laden
 * }
 * ```
 */
export function useConsent(): ConsentContextValue;
export function useConsent(
  category: ConsentCategory
): ConsentContextValue & { allowed: boolean };
export function useConsent(category?: ConsentCategory) {
  const context = useContext(ConsentContext);

  if (!context) {
    throw new Error('useConsent must be used within a ConsentProvider');
  }

  if (category) {
    return {
      ...context,
      allowed: context.hasConsent(category),
    };
  }

  return context;
}

/**
 * useConsentManager - Direkter Zugriff auf ConsentManager
 */
export function useConsentManager(): ConsentManager | null {
  const context = useContext(ConsentContext);
  return context?.manager ?? null;
}

// =============================================================================
// Components
// =============================================================================

interface ConsentGateProps {
  /** Erforderliche Kategorie */
  category: ConsentCategory;

  /** Inhalt bei Consent */
  children: ReactNode;

  /** Inhalt ohne Consent */
  placeholder?: ReactNode;

  /** Fallback waehrend Laden */
  fallback?: ReactNode;
}

/**
 * ConsentGate - Zeigt Inhalt nur bei Consent
 *
 * @example
 * ```tsx
 * <ConsentGate
 *   category="analytics"
 *   placeholder={<ConsentPlaceholder category="analytics" />}
 * >
 *   <GoogleAnalytics />
 * </ConsentGate>
 * ```
 */
export const ConsentGate: FC<ConsentGateProps> = ({
  category,
  children,
  placeholder = null,
  fallback = null,
}) => {
  const { hasConsent, isLoading } = useConsent();

  if (isLoading) {
    return <>{fallback}</>;
  }

  if (!hasConsent(category)) {
    return <>{placeholder}</>;
  }

  return <>{children}</>;
};

interface ConsentPlaceholderProps {
  /** Kategorie */
  category: ConsentCategory;

  /** Custom Nachricht */
  message?: string;

  /** Custom Button-Text */
  buttonText?: string;

  /** Custom Styling */
  className?: string;
}

/**
 * ConsentPlaceholder - Placeholder fuer blockierten Inhalt
 */
export const ConsentPlaceholder: FC<ConsentPlaceholderProps> = ({
  category,
  message,
  buttonText,
  className = '',
}) => {
  const { showSettings } = useConsent();

  const categoryNames: Record<ConsentCategory, string> = {
    essential: 'Essentielle Cookies',
    functional: 'Funktionale Cookies',
    analytics: 'Statistik-Cookies',
    marketing: 'Marketing-Cookies',
    social: 'Social Media-Cookies',
  };

  const defaultMessage = `Dieser Inhalt erfordert ${categoryNames[category]}.`;

  return (
    <div className={`bp-consent-placeholder ${className}`}>
      <p>{message || defaultMessage}</p>
      <button type="button" onClick={showSettings}>
        {buttonText || 'Cookie-Einstellungen oeffnen'}
      </button>
    </div>
  );
};

// =============================================================================
// Banner Component (Headless)
// =============================================================================

interface ConsentBannerRenderProps {
  /** Ist Banner sichtbar? */
  isVisible: boolean;

  /** Aktueller Consent */
  consent: ConsentState | null;

  /** Wird Consent benoetigt? */
  needsConsent: boolean;

  /** Alle akzeptieren */
  onAcceptAll: () => void;

  /** Alle ablehnen */
  onRejectAll: () => void;

  /** Auswahl speichern */
  onSaveSelection: (categories: Partial<ConsentCategories>) => void;

  /** Einstellungen oeffnen */
  onShowSettings: () => void;

  /** Banner schliessen */
  onClose: () => void;
}

interface ConsentBannerProps {
  /** Render-Funktion fuer Custom UI */
  render?: (props: ConsentBannerRenderProps) => ReactNode;

  /** Custom Styling */
  className?: string;
}

/**
 * ConsentBanner - Headless Banner-Komponente
 *
 * Kann mit eigener UI gerendert werden oder nutzt Default-UI.
 *
 * @example
 * ```tsx
 * // Mit eigener UI
 * <ConsentBanner
 *   render={({ isVisible, onAcceptAll, onRejectAll }) => (
 *     isVisible && (
 *       <div className="my-banner">
 *         <button onClick={onAcceptAll}>Accept</button>
 *         <button onClick={onRejectAll}>Reject</button>
 *       </div>
 *     )
 *   )}
 * />
 *
 * // Mit Default-UI
 * <ConsentBanner />
 * ```
 */
export const ConsentBanner: FC<ConsentBannerProps> = ({ render, className }) => {
  const {
    consent,
    isBannerVisible,
    needsConsent,
    acceptAll,
    rejectAll,
    saveSelection,
    showSettings,
    hideBanner,
  } = useConsent();

  const renderProps: ConsentBannerRenderProps = {
    isVisible: isBannerVisible,
    consent,
    needsConsent,
    onAcceptAll: acceptAll,
    onRejectAll: rejectAll,
    onSaveSelection: saveSelection,
    onShowSettings: showSettings,
    onClose: hideBanner,
  };

  // Custom Render
  if (render) {
    return <>{render(renderProps)}</>;
  }

  // Default UI
  if (!isBannerVisible) {
    return null;
  }

  return (
    <div
      className={`bp-consent-banner ${className || ''}`}
      role="dialog"
      aria-modal="true"
      aria-label="Cookie-Einstellungen"
    >
      <div className="bp-consent-banner-content">
        <h2>Datenschutzeinstellungen</h2>
        <p>
          Wir nutzen Cookies und aehnliche Technologien, um Ihnen ein optimales
          Nutzererlebnis zu bieten.
        </p>

        <div className="bp-consent-banner-actions">
          <button
            type="button"
            className="bp-consent-btn bp-consent-btn-reject"
            onClick={rejectAll}
          >
            Alle ablehnen
          </button>
          <button
            type="button"
            className="bp-consent-btn bp-consent-btn-settings"
            onClick={showSettings}
          >
            Einstellungen
          </button>
          <button
            type="button"
            className="bp-consent-btn bp-consent-btn-accept"
            onClick={acceptAll}
          >
            Alle akzeptieren
          </button>
        </div>
      </div>
    </div>
  );
};

// =============================================================================
// Exports
// =============================================================================

export { ConsentContext };
export type { ConsentContextValue, ConsentBannerRenderProps };
