/**
 * Cookie Consent Management
 *
 * Shared consent functionality for CounterMeasure applications.
 * Handles cookie consent banner, preferences modal, and consent API integration.
 */

// Types
export interface ConsentCategories {
  essential: boolean
  performance: boolean
  analytics: boolean
  advertising: boolean
  social_media: boolean
}

export interface CategoryInfo {
  id: string
  name: string
  description: string
  required: boolean
  cookies: CookieInfo[]
}

export interface CookieInfo {
  name: string
  provider: string
  cookie_type: string
  description: string | null
  duration: string | null
}

export interface ConsentResponse {
  visitor_id: string
  categories: ConsentCategories
  consent_date: string
  expires_at: string | null
}

interface CategoriesApiResponse {
  categories: CategoryInfo[]
}

interface ConsentApiResponse {
  consent: ConsentResponse | null
}

export interface ConsentConfig {
  visitorIdKey?: string
  consentKey?: string
  apiBasePath?: string
  cookieMaxAge?: number
}

const DEFAULT_CONFIG: Required<ConsentConfig> = {
  visitorIdKey: 'tf_visitor_id',
  consentKey: 'tf_consent',
  apiBasePath: '/api/v1/consent',
  cookieMaxAge: 31536000, // 1 year
}

/**
 * Create a consent manager instance with the given configuration.
 */
export function createConsentManager(userConfig: ConsentConfig = {}) {
  const config = { ...DEFAULT_CONFIG, ...userConfig }

  function generateVisitorId(): string {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
      const r = (Math.random() * 16) | 0
      const v = c === 'x' ? r : (r & 0x3) | 0x8
      return v.toString(16)
    })
  }

  function getVisitorId(): string {
    const visitorId = localStorage.getItem(config.visitorIdKey)
    if (visitorId !== null && visitorId !== '') {
      return visitorId
    }
    const newVisitorId = generateVisitorId()
    localStorage.setItem(config.visitorIdKey, newVisitorId)
    document.cookie = `${config.visitorIdKey}=${newVisitorId}; path=/; max-age=${String(config.cookieMaxAge)}; SameSite=Lax`
    return newVisitorId
  }

  function getStoredConsent(): ConsentCategories | null {
    const stored = localStorage.getItem(config.consentKey)
    if (stored !== null && stored !== '') {
      try {
        return JSON.parse(stored) as ConsentCategories
      } catch {
        return null
      }
    }
    return null
  }

  function setStoredConsent(categories: ConsentCategories): void {
    localStorage.setItem(config.consentKey, JSON.stringify(categories))
  }

  async function fetchCategories(): Promise<CategoryInfo[]> {
    try {
      const response = await fetch(`${config.apiBasePath}/categories`)
      if (!response.ok) {
        throw new Error('Failed to fetch categories')
      }
      const data = (await response.json()) as CategoriesApiResponse
      return data.categories
    } catch (error: unknown) {
      console.error('Error fetching consent categories:', error)
      return []
    }
  }

  async function checkConsent(): Promise<ConsentResponse | null> {
    try {
      const response = await fetch(config.apiBasePath, {
        headers: {
          'X-Visitor-ID': getVisitorId(),
        },
      })
      if (!response.ok) {
        throw new Error('Failed to check consent')
      }
      const data = (await response.json()) as ConsentApiResponse
      return data.consent
    } catch (error: unknown) {
      console.error('Error checking consent:', error)
      return null
    }
  }

  async function saveConsent(
    categories: ConsentCategories,
    consentMethod = 'banner'
  ): Promise<boolean> {
    try {
      const visitorId = getVisitorId()
      const response = await fetch(config.apiBasePath, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Visitor-ID': visitorId,
        },
        body: JSON.stringify({
          visitor_id: visitorId,
          categories,
          consent_method: consentMethod,
        }),
      })
      if (!response.ok) {
        throw new Error('Failed to save consent')
      }
      setStoredConsent(categories)
      return true
    } catch (error: unknown) {
      console.error('Error saving consent:', error)
      return false
    }
  }

  function acceptAll(): ConsentCategories {
    return {
      essential: true,
      performance: true,
      analytics: true,
      advertising: true,
      social_media: true,
    }
  }

  function rejectAll(): ConsentCategories {
    return {
      essential: true,
      performance: false,
      analytics: false,
      advertising: false,
      social_media: false,
    }
  }

  return {
    generateVisitorId,
    getVisitorId,
    getStoredConsent,
    setStoredConsent,
    fetchCategories,
    checkConsent,
    saveConsent,
    acceptAll,
    rejectAll,
    config,
  }
}

// Default instance for simple usage
let defaultManager: ReturnType<typeof createConsentManager> | null = null

export function getDefaultConsentManager(config?: ConsentConfig) {
  defaultManager ??= createConsentManager(config)
  return defaultManager
}

// Re-export convenience functions using default manager
export const generateVisitorId = () => getDefaultConsentManager().generateVisitorId()
export const getVisitorId = () => getDefaultConsentManager().getVisitorId()
export const getStoredConsent = () => getDefaultConsentManager().getStoredConsent()
export const setStoredConsent = (categories: ConsentCategories) => {
  getDefaultConsentManager().setStoredConsent(categories)
}
export const fetchCategories = () => getDefaultConsentManager().fetchCategories()
export const checkConsent = () => getDefaultConsentManager().checkConsent()
export const saveConsent = (categories: ConsentCategories, method?: string) =>
  getDefaultConsentManager().saveConsent(categories, method)
export const acceptAll = () => getDefaultConsentManager().acceptAll()
export const rejectAll = () => getDefaultConsentManager().rejectAll()
