/**
 * Vue 3 Integration fuer @breakpilot/consent-sdk
 *
 * @example
 * ```vue
 * <script setup>
 * import { useConsent, ConsentBanner, ConsentGate } from '@breakpilot/consent-sdk/vue';
 *
 * const { hasConsent, acceptAll, rejectAll } = useConsent();
 * </script>
 *
 * <template>
 *   <ConsentBanner />
 *   <ConsentGate category="analytics">
 *     <AnalyticsComponent />
 *   </ConsentGate>
 * </template>
 * ```
 */

import {
  ref,
  computed,
  readonly,
  inject,
  provide,
  onMounted,
  onUnmounted,
  defineComponent,
  h,
  type Ref,
  type InjectionKey,
  type PropType,
} from 'vue';
import { ConsentManager } from '../core/ConsentManager';
import type {
  ConsentConfig,
  ConsentState,
  ConsentCategory,
  ConsentCategories,
} from '../types';

// =============================================================================
// Injection Key
// =============================================================================

const CONSENT_KEY: InjectionKey<ConsentContext> = Symbol('consent');

// =============================================================================
// Types
// =============================================================================

interface ConsentContext {
  manager: Ref<ConsentManager | null>;
  consent: Ref<ConsentState | null>;
  isInitialized: Ref<boolean>;
  isLoading: Ref<boolean>;
  isBannerVisible: Ref<boolean>;
  needsConsent: Ref<boolean>;
  hasConsent: (category: ConsentCategory) => boolean;
  acceptAll: () => Promise<void>;
  rejectAll: () => Promise<void>;
  saveSelection: (categories: Partial<ConsentCategories>) => Promise<void>;
  showBanner: () => void;
  hideBanner: () => void;
  showSettings: () => void;
}

// =============================================================================
// Composable: useConsent
// =============================================================================

/**
 * Haupt-Composable fuer Consent-Zugriff
 *
 * @example
 * ```vue
 * <script setup>
 * const { hasConsent, acceptAll } = useConsent();
 *
 * if (hasConsent('analytics')) {
 *   // Analytics laden
 * }
 * </script>
 * ```
 */
export function useConsent(): ConsentContext {
  const context = inject(CONSENT_KEY);

  if (!context) {
    throw new Error(
      'useConsent() must be used within a component that has called provideConsent() or is wrapped in ConsentProvider'
    );
  }

  return context;
}

/**
 * Consent-Provider einrichten (in App.vue aufrufen)
 *
 * @example
 * ```vue
 * <script setup>
 * import { provideConsent } from '@breakpilot/consent-sdk/vue';
 *
 * provideConsent({
 *   apiEndpoint: 'https://consent.example.com/api/v1',
 *   siteId: 'site_abc123',
 * });
 * </script>
 * ```
 */
export function provideConsent(config: ConsentConfig): ConsentContext {
  const manager = ref<ConsentManager | null>(null);
  const consent = ref<ConsentState | null>(null);
  const isInitialized = ref(false);
  const isLoading = ref(true);
  const isBannerVisible = ref(false);

  const needsConsent = computed(() => {
    return manager.value?.needsConsent() ?? true;
  });

  // Initialisierung
  onMounted(async () => {
    const consentManager = new ConsentManager(config);
    manager.value = consentManager;

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

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

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

    try {
      await consentManager.init();
      consent.value = consentManager.getConsent();
      isInitialized.value = true;
      isBannerVisible.value = consentManager.isBannerVisible();
    } catch (error) {
      console.error('Failed to initialize ConsentManager:', error);
    } finally {
      isLoading.value = false;
    }

    // Cleanup bei Unmount
    onUnmounted(() => {
      unsubChange();
      unsubBannerShow();
      unsubBannerHide();
    });
  });

  // Methoden
  const hasConsent = (category: ConsentCategory): boolean => {
    return manager.value?.hasConsent(category) ?? category === 'essential';
  };

  const acceptAll = async (): Promise<void> => {
    await manager.value?.acceptAll();
  };

  const rejectAll = async (): Promise<void> => {
    await manager.value?.rejectAll();
  };

  const saveSelection = async (categories: Partial<ConsentCategories>): Promise<void> => {
    await manager.value?.setConsent(categories);
    manager.value?.hideBanner();
  };

  const showBanner = (): void => {
    manager.value?.showBanner();
  };

  const hideBanner = (): void => {
    manager.value?.hideBanner();
  };

  const showSettings = (): void => {
    manager.value?.showSettings();
  };

  const context: ConsentContext = {
    manager: readonly(manager) as Ref<ConsentManager | null>,
    consent: readonly(consent) as Ref<ConsentState | null>,
    isInitialized: readonly(isInitialized),
    isLoading: readonly(isLoading),
    isBannerVisible: readonly(isBannerVisible),
    needsConsent,
    hasConsent,
    acceptAll,
    rejectAll,
    saveSelection,
    showBanner,
    hideBanner,
    showSettings,
  };

  provide(CONSENT_KEY, context);

  return context;
}

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

/**
 * ConsentProvider - Wrapper-Komponente
 *
 * @example
 * ```vue
 * <ConsentProvider :config="config">
 *   <App />
 * </ConsentProvider>
 * ```
 */
export const ConsentProvider = defineComponent({
  name: 'ConsentProvider',
  props: {
    config: {
      type: Object as PropType<ConsentConfig>,
      required: true,
    },
  },
  setup(props, { slots }) {
    provideConsent(props.config);
    return () => slots.default?.();
  },
});

/**
 * ConsentGate - Zeigt Inhalt nur bei Consent
 *
 * @example
 * ```vue
 * <ConsentGate category="analytics">
 *   <template #default>
 *     <AnalyticsComponent />
 *   </template>
 *   <template #placeholder>
 *     <p>Bitte akzeptieren Sie Statistik-Cookies.</p>
 *   </template>
 * </ConsentGate>
 * ```
 */
export const ConsentGate = defineComponent({
  name: 'ConsentGate',
  props: {
    category: {
      type: String as PropType<ConsentCategory>,
      required: true,
    },
  },
  setup(props, { slots }) {
    const { hasConsent, isLoading } = useConsent();

    return () => {
      if (isLoading.value) {
        return slots.fallback?.() ?? null;
      }

      if (!hasConsent(props.category)) {
        return slots.placeholder?.() ?? null;
      }

      return slots.default?.();
    };
  },
});

/**
 * ConsentPlaceholder - Placeholder fuer blockierten Inhalt
 *
 * @example
 * ```vue
 * <ConsentPlaceholder category="marketing" />
 * ```
 */
export const ConsentPlaceholder = defineComponent({
  name: 'ConsentPlaceholder',
  props: {
    category: {
      type: String as PropType<ConsentCategory>,
      required: true,
    },
    message: {
      type: String,
      default: '',
    },
    buttonText: {
      type: String,
      default: 'Cookie-Einstellungen öffnen',
    },
  },
  setup(props) {
    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 displayMessage = computed(() => {
      return props.message || `Dieser Inhalt erfordert ${categoryNames[props.category]}.`;
    });

    return () =>
      h('div', { class: 'bp-consent-placeholder' }, [
        h('p', displayMessage.value),
        h(
          'button',
          {
            type: 'button',
            onClick: showSettings,
          },
          props.buttonText
        ),
      ]);
  },
});

/**
 * ConsentBanner - Cookie-Banner Komponente
 *
 * @example
 * ```vue
 * <ConsentBanner>
 *   <template #default="{ isVisible, onAcceptAll, onRejectAll, onShowSettings }">
 *     <div v-if="isVisible" class="my-banner">
 *       <button @click="onAcceptAll">Accept</button>
 *       <button @click="onRejectAll">Reject</button>
 *     </div>
 *   </template>
 * </ConsentBanner>
 * ```
 */
export const ConsentBanner = defineComponent({
  name: 'ConsentBanner',
  setup(_, { slots }) {
    const {
      consent,
      isBannerVisible,
      needsConsent,
      acceptAll,
      rejectAll,
      saveSelection,
      showSettings,
      hideBanner,
    } = useConsent();

    const slotProps = computed(() => ({
      isVisible: isBannerVisible.value,
      consent: consent.value,
      needsConsent: needsConsent.value,
      onAcceptAll: acceptAll,
      onRejectAll: rejectAll,
      onSaveSelection: saveSelection,
      onShowSettings: showSettings,
      onClose: hideBanner,
    }));

    return () => {
      // Custom Slot
      if (slots.default) {
        return slots.default(slotProps.value);
      }

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

      return h(
        'div',
        {
          class: 'bp-consent-banner',
          role: 'dialog',
          'aria-modal': 'true',
          'aria-label': 'Cookie-Einstellungen',
        },
        [
          h('div', { class: 'bp-consent-banner-content' }, [
            h('h2', 'Datenschutzeinstellungen'),
            h(
              'p',
              'Wir nutzen Cookies und ähnliche Technologien, um Ihnen ein optimales Nutzererlebnis zu bieten.'
            ),
            h('div', { class: 'bp-consent-banner-actions' }, [
              h(
                'button',
                {
                  type: 'button',
                  class: 'bp-consent-btn bp-consent-btn-reject',
                  onClick: rejectAll,
                },
                'Alle ablehnen'
              ),
              h(
                'button',
                {
                  type: 'button',
                  class: 'bp-consent-btn bp-consent-btn-settings',
                  onClick: showSettings,
                },
                'Einstellungen'
              ),
              h(
                'button',
                {
                  type: 'button',
                  class: 'bp-consent-btn bp-consent-btn-accept',
                  onClick: acceptAll,
                },
                'Alle akzeptieren'
              ),
            ]),
          ]),
        ]
      );
    };
  },
});

// =============================================================================
// Plugin
// =============================================================================

/**
 * Vue Plugin fuer globale Installation
 *
 * @example
 * ```ts
 * import { createApp } from 'vue';
 * import { ConsentPlugin } from '@breakpilot/consent-sdk/vue';
 *
 * const app = createApp(App);
 * app.use(ConsentPlugin, {
 *   apiEndpoint: 'https://consent.example.com/api/v1',
 *   siteId: 'site_abc123',
 * });
 * ```
 */
export const ConsentPlugin = {
  install(app: { provide: (key: symbol | string, value: unknown) => void }, config: ConsentConfig) {
    const manager = new ConsentManager(config);
    const consent = ref<ConsentState | null>(null);
    const isInitialized = ref(false);
    const isLoading = ref(true);
    const isBannerVisible = ref(false);

    // Initialisieren
    manager.init().then(() => {
      consent.value = manager.getConsent();
      isInitialized.value = true;
      isLoading.value = false;
      isBannerVisible.value = manager.isBannerVisible();
    });

    // Events
    manager.on('change', (newConsent) => {
      consent.value = newConsent;
    });
    manager.on('banner_show', () => {
      isBannerVisible.value = true;
    });
    manager.on('banner_hide', () => {
      isBannerVisible.value = false;
    });

    const context: ConsentContext = {
      manager: ref(manager) as Ref<ConsentManager | null>,
      consent: consent as Ref<ConsentState | null>,
      isInitialized,
      isLoading,
      isBannerVisible,
      needsConsent: computed(() => manager.needsConsent()),
      hasConsent: (category: ConsentCategory) => manager.hasConsent(category),
      acceptAll: () => manager.acceptAll(),
      rejectAll: () => manager.rejectAll(),
      saveSelection: async (categories: Partial<ConsentCategories>) => {
        await manager.setConsent(categories);
        manager.hideBanner();
      },
      showBanner: () => manager.showBanner(),
      hideBanner: () => manager.hideBanner(),
      showSettings: () => manager.showSettings(),
    };

    app.provide(CONSENT_KEY, context);
  },
};

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

export { CONSENT_KEY };
export type { ConsentContext };
