/**
 * ConsentStorage - Lokale Speicherung des Consent-Status
 *
 * Speichert Consent-Daten im localStorage mit HMAC-Signatur
 * zur Manipulationserkennung.
 */

import type { ConsentConfig, ConsentState } from '../types';

const STORAGE_KEY = 'bp_consent';
const STORAGE_VERSION = '1';

/**
 * Gespeichertes Format
 */
interface StoredConsent {
  version: string;
  consent: ConsentState;
  signature: string;
}

/**
 * ConsentStorage - Persistente Speicherung
 */
export class ConsentStorage {
  private config: ConsentConfig;
  private storageKey: string;

  constructor(config: ConsentConfig) {
    this.config = config;
    // Pro Site ein separater Key
    this.storageKey = `${STORAGE_KEY}_${config.siteId}`;
  }

  /**
   * Consent laden
   */
  get(): ConsentState | null {
    if (typeof window === 'undefined') {
      return null;
    }

    try {
      const raw = localStorage.getItem(this.storageKey);
      if (!raw) {
        return null;
      }

      const stored: StoredConsent = JSON.parse(raw);

      // Version pruefen
      if (stored.version !== STORAGE_VERSION) {
        this.log('Storage version mismatch, clearing');
        this.clear();
        return null;
      }

      // Signatur pruefen
      if (!this.verifySignature(stored.consent, stored.signature)) {
        this.log('Invalid signature, clearing');
        this.clear();
        return null;
      }

      return stored.consent;
    } catch (error) {
      this.log('Failed to load consent:', error);
      return null;
    }
  }

  /**
   * Consent speichern
   */
  set(consent: ConsentState): void {
    if (typeof window === 'undefined') {
      return;
    }

    try {
      const signature = this.generateSignature(consent);

      const stored: StoredConsent = {
        version: STORAGE_VERSION,
        consent,
        signature,
      };

      localStorage.setItem(this.storageKey, JSON.stringify(stored));

      // Auch als Cookie setzen (fuer Server-Side Rendering)
      this.setCookie(consent);

      this.log('Consent saved to storage');
    } catch (error) {
      this.log('Failed to save consent:', error);
    }
  }

  /**
   * Consent loeschen
   */
  clear(): void {
    if (typeof window === 'undefined') {
      return;
    }

    try {
      localStorage.removeItem(this.storageKey);
      this.clearCookie();
      this.log('Consent cleared from storage');
    } catch (error) {
      this.log('Failed to clear consent:', error);
    }
  }

  /**
   * Pruefen ob Consent existiert
   */
  exists(): boolean {
    return this.get() !== null;
  }

  // ===========================================================================
  // Cookie Management
  // ===========================================================================

  /**
   * Consent als Cookie setzen
   */
  private setCookie(consent: ConsentState): void {
    const days = this.config.consent?.rememberDays ?? 365;
    const expires = new Date();
    expires.setDate(expires.getDate() + days);

    // Nur Kategorien als Cookie (fuer SSR)
    const cookieValue = JSON.stringify(consent.categories);
    const encoded = encodeURIComponent(cookieValue);

    document.cookie = [
      `${this.storageKey}=${encoded}`,
      `expires=${expires.toUTCString()}`,
      'path=/',
      'SameSite=Lax',
      location.protocol === 'https:' ? 'Secure' : '',
    ]
      .filter(Boolean)
      .join('; ');
  }

  /**
   * Cookie loeschen
   */
  private clearCookie(): void {
    document.cookie = `${this.storageKey}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
  }

  // ===========================================================================
  // Signature (Simple HMAC-like)
  // ===========================================================================

  /**
   * Signatur generieren
   */
  private generateSignature(consent: ConsentState): string {
    const data = JSON.stringify(consent);
    const key = this.config.siteId;

    // Einfache Hash-Funktion (fuer Client-Side)
    // In Produktion wuerde man SubtleCrypto verwenden
    return this.simpleHash(data + key);
  }

  /**
   * Signatur verifizieren
   */
  private verifySignature(consent: ConsentState, signature: string): boolean {
    const expected = this.generateSignature(consent);
    return expected === signature;
  }

  /**
   * Einfache Hash-Funktion (djb2)
   */
  private simpleHash(str: string): string {
    let hash = 5381;
    for (let i = 0; i < str.length; i++) {
      hash = (hash * 33) ^ str.charCodeAt(i);
    }
    return (hash >>> 0).toString(16);
  }

  /**
   * Debug-Logging
   */
  private log(...args: unknown[]): void {
    if (this.config.debug) {
      console.log('[ConsentStorage]', ...args);
    }
  }
}

export default ConsentStorage;
