import { test, expect } from '@playwright/test'

/**
 * Banner Consent API Integration Tests
 *
 * Tests the complete lifecycle of cookie banner consents:
 * - Record/retrieve/withdraw consent
 * - Email linking for DSR integration
 * - Consent export (Art. 15/20 DSGVO)
 * - Consent deletion (Art. 17 DSGVO erasure)
 * - Consent sync to Einwilligungen
 * - Vendor sync from service registry
 * - Site config with config_version for consent proof
 */

const API_BASE = process.env.PLAYWRIGHT_API_URL || 'https://macmini:8093'
const TENANT_ID = '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e'
const HEADERS = {
  'Content-Type': 'application/json',
  'X-Tenant-ID': TENANT_ID,
}

// Test data
const TEST_SITE_ID = `e2e-banner-test-${Date.now()}`
const TEST_DEVICE_FP = `e2e-device-${Date.now()}`
const TEST_EMAIL = `e2e-test-${Date.now()}@example.com`

test.describe('Banner Consent API — Full Lifecycle', () => {
  let siteConfigId: string | null = null
  let consentId: string | null = null

  // ─── Setup: Create site config ───────────────────────────
  test('01 — Create site config', async ({ request }) => {
    const res = await request.post(`${API_BASE}/banner/admin/sites`, {
      headers: HEADERS,
      data: {
        site_id: TEST_SITE_ID,
        site_name: 'E2E Test Site',
        site_url: 'https://e2e-test.example.com',
        banner_title: 'Cookie-Einstellungen',
        banner_description: 'Wir verwenden Cookies fuer E2E Tests.',
        privacy_url: '/datenschutz',
        imprint_url: '/impressum',
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.site_id).toBe(TEST_SITE_ID)
    expect(body.config_version).toBe(1)
    siteConfigId = body.id
  })

  test('02 — Create categories for site', async ({ request }) => {
    const categories = [
      { category_key: 'necessary', name_de: 'Notwendig', is_required: true, sort_order: 0 },
      { category_key: 'statistics', name_de: 'Statistik', is_required: false, sort_order: 1 },
      { category_key: 'marketing', name_de: 'Marketing', is_required: false, sort_order: 2 },
    ]
    for (const cat of categories) {
      const res = await request.post(`${API_BASE}/banner/admin/sites/${TEST_SITE_ID}/categories`, {
        headers: HEADERS,
        data: cat,
      })
      expect(res.ok()).toBeTruthy()
    }
  })

  test('03 — Create vendor configs', async ({ request }) => {
    const vendors = [
      { vendor_name: 'Google Analytics', category_key: 'statistics', retention_days: 790, cookie_names: ['_ga', '_gid'] },
      { vendor_name: 'Facebook Pixel', category_key: 'marketing', retention_days: 90, cookie_names: ['_fbp'] },
    ]
    for (const v of vendors) {
      const res = await request.post(`${API_BASE}/banner/admin/sites/${TEST_SITE_ID}/vendors`, {
        headers: HEADERS,
        data: v,
      })
      expect(res.ok()).toBeTruthy()
    }
  })

  // ─── Core Consent CRUD ───────────────────────────────────
  test('04 — Get site config for banner display', async ({ request }) => {
    const res = await request.get(`${API_BASE}/banner/config/${TEST_SITE_ID}`, { headers: HEADERS })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.site_id).toBe(TEST_SITE_ID)
    expect(body.banner_title).toBe('Cookie-Einstellungen')
    expect(body.categories.length).toBe(3)
    expect(body.vendors.length).toBe(2)
    expect(body.config_version).toBe(1)
  })

  test('05 — Record consent (accept statistics only)', async ({ request }) => {
    const res = await request.post(`${API_BASE}/banner/consent`, {
      headers: HEADERS,
      data: {
        site_id: TEST_SITE_ID,
        device_fingerprint: TEST_DEVICE_FP,
        categories: ['necessary', 'statistics'],
        vendors: ['Google Analytics'],
        ip_address: '192.168.1.100',
        user_agent: 'Playwright E2E Test',
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.device_fingerprint).toBe(TEST_DEVICE_FP)
    expect(body.categories).toEqual(['necessary', 'statistics'])
    expect(body.vendors).toEqual(['Google Analytics'])
    expect(body.ip_hash).toBeTruthy() // IP is hashed
    expect(body.linked_email).toBeNull()
    consentId = body.id
  })

  test('06 — Retrieve consent for device', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent?site_id=${TEST_SITE_ID}&device_fingerprint=${TEST_DEVICE_FP}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.has_consent).toBe(true)
    expect(body.consent.categories).toEqual(['necessary', 'statistics'])
  })

  test('07 — Update consent (accept all categories)', async ({ request }) => {
    const res = await request.post(`${API_BASE}/banner/consent`, {
      headers: HEADERS,
      data: {
        site_id: TEST_SITE_ID,
        device_fingerprint: TEST_DEVICE_FP,
        categories: ['necessary', 'statistics', 'marketing'],
        vendors: ['Google Analytics', 'Facebook Pixel'],
        ip_address: '192.168.1.100',
        user_agent: 'Playwright E2E Test',
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.categories).toEqual(['necessary', 'statistics', 'marketing'])
    expect(body.id).toBe(consentId) // Same consent row (upsert)
  })

  // ─── Phase 3: Email Linking ──────────────────────────────
  test('08 — Link email to device fingerprint', async ({ request }) => {
    const res = await request.post(`${API_BASE}/banner/consent/link-email`, {
      headers: HEADERS,
      data: {
        site_id: TEST_SITE_ID,
        device_fingerprint: TEST_DEVICE_FP,
        email: TEST_EMAIL,
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.linked_email).toBe(TEST_EMAIL.toLowerCase())
    expect(body.device_fingerprint).toBe(TEST_DEVICE_FP)
  })

  test('09 — Find consents by email (Art. 15)', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent/by-email/${encodeURIComponent(TEST_EMAIL)}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.length).toBe(1)
    expect(body[0].linked_email).toBe(TEST_EMAIL.toLowerCase())
    expect(body[0].device_fingerprint).toBe(TEST_DEVICE_FP)
  })

  test('10 — Export consent data for DSR (Art. 15/20)', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent/dsr-export/${encodeURIComponent(TEST_EMAIL)}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.email).toBe(TEST_EMAIL.toLowerCase())
    expect(body.banner_consents.length).toBe(1)
    expect(body.audit_trail.length).toBeGreaterThan(0)
    // Verify consent proof fields in audit trail
    const lastAudit = body.audit_trail[0]
    expect(lastAudit.action).toBeTruthy()
    expect(lastAudit.site_id).toBe(TEST_SITE_ID)
  })

  // ─── Phase 4: Consent Sync ──────────────────────────────
  test('11 — Sync banner consent to Einwilligungen', async ({ request }) => {
    const res = await request.post(`${API_BASE}/banner/consent/sync`, {
      headers: HEADERS,
      data: {
        site_id: TEST_SITE_ID,
        device_fingerprint: TEST_DEVICE_FP,
        email: TEST_EMAIL,
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.synced).toBeGreaterThan(0)
    expect(body.categories).toContain('necessary')
    expect(body.categories).toContain('statistics')
    expect(body.categories).toContain('marketing')
    expect(body.email).toBe(TEST_EMAIL.toLowerCase())
  })

  // ─── DSGVO Export ────────────────────────────────────────
  test('12 — Export consent per device (existing endpoint)', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent/export?site_id=${TEST_SITE_ID}&device_fingerprint=${TEST_DEVICE_FP}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.device_fingerprint).toBe(TEST_DEVICE_FP)
    expect(body.consents.length).toBe(1)
    expect(body.audit_trail.length).toBeGreaterThan(0)
  })

  // ─── Stats ───────────────────────────────────────────────
  test('13 — Get site consent statistics', async ({ request }) => {
    const res = await request.get(`${API_BASE}/banner/admin/stats/${TEST_SITE_ID}`, {
      headers: HEADERS,
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.site_id).toBe(TEST_SITE_ID)
    expect(body.total_consents).toBeGreaterThan(0)
    expect(body.category_acceptance.necessary).toBeTruthy()
    expect(body.category_acceptance.statistics).toBeTruthy()
  })

  // ─── Withdraw + Cleanup ─────────────────────────────────
  test('14 — Withdraw consent', async ({ request }) => {
    expect(consentId).toBeTruthy()
    const res = await request.delete(`${API_BASE}/banner/consent/${consentId}`, {
      headers: HEADERS,
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.success).toBe(true)
  })

  test('15 — Verify consent withdrawn (no consent found)', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent?site_id=${TEST_SITE_ID}&device_fingerprint=${TEST_DEVICE_FP}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.has_consent).toBe(false)
  })

  // ─── Cleanup: Delete site config ────────────────────────
  test('16 — Cleanup: Delete test site', async ({ request }) => {
    const res = await request.delete(`${API_BASE}/banner/admin/sites/${TEST_SITE_ID}`, {
      headers: HEADERS,
    })
    expect(res.status()).toBe(204)
  })
})


test.describe('Banner Consent API — Art. 17 Erasure via Email', () => {
  const ERASURE_SITE = `e2e-erasure-${Date.now()}`
  const ERASURE_DEVICE_1 = `e2e-dev1-${Date.now()}`
  const ERASURE_DEVICE_2 = `e2e-dev2-${Date.now()}`
  const ERASURE_EMAIL = `erasure-${Date.now()}@example.com`

  test.beforeAll(async ({ request }) => {
    // Create site
    await request.post(`${API_BASE}/banner/admin/sites`, {
      headers: HEADERS,
      data: { site_id: ERASURE_SITE, site_name: 'Erasure Test Site' },
    })
    // Record consent on two devices with same email
    for (const fp of [ERASURE_DEVICE_1, ERASURE_DEVICE_2]) {
      await request.post(`${API_BASE}/banner/consent`, {
        headers: HEADERS,
        data: {
          site_id: ERASURE_SITE,
          device_fingerprint: fp,
          categories: ['necessary', 'statistics'],
          vendors: [],
        },
      })
      await request.post(`${API_BASE}/banner/consent/link-email`, {
        headers: HEADERS,
        data: { site_id: ERASURE_SITE, device_fingerprint: fp, email: ERASURE_EMAIL },
      })
    }
  })

  test('should find 2 consents for email', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent/by-email/${encodeURIComponent(ERASURE_EMAIL)}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.length).toBe(2)
  })

  test('should delete all consents by email (Art. 17)', async ({ request }) => {
    const res = await request.delete(
      `${API_BASE}/banner/consent/by-email/${encodeURIComponent(ERASURE_EMAIL)}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.deleted).toBe(2)
    expect(body.email).toBe(ERASURE_EMAIL.toLowerCase())
  })

  test('should find 0 consents after erasure', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent/by-email/${encodeURIComponent(ERASURE_EMAIL)}`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.length).toBe(0)
  })

  test.afterAll(async ({ request }) => {
    await request.delete(`${API_BASE}/banner/admin/sites/${ERASURE_SITE}`, {
      headers: HEADERS,
    })
  })
})


test.describe('Banner Consent API — Vendor Sync from Registry', () => {
  const SYNC_SITE = `e2e-sync-${Date.now()}`

  test.beforeAll(async ({ request }) => {
    await request.post(`${API_BASE}/banner/admin/sites`, {
      headers: HEADERS,
      data: { site_id: SYNC_SITE, site_name: 'Vendor Sync Test' },
    })
  })

  test('should sync vendors from service registry', async ({ request }) => {
    const res = await request.post(
      `${API_BASE}/banner/admin/sites/${SYNC_SITE}/sync-vendors`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.total).toBeGreaterThan(0)
    expect(body.created).toBeGreaterThan(0)
  })

  test('should list synced vendors', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/admin/sites/${SYNC_SITE}/vendors`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const vendors = await res.json()
    expect(vendors.length).toBeGreaterThan(0)

    // Verify vendor structure
    const ga = vendors.find((v: any) => v.vendor_name === 'Google Analytics')
    if (ga) {
      expect(ga.category_key).toBe('statistics')
      expect(ga.retention_days).toBe(790) // 26 months
    }
  })

  test.afterAll(async ({ request }) => {
    await request.delete(`${API_BASE}/banner/admin/sites/${SYNC_SITE}`, {
      headers: HEADERS,
    })
  })
})


test.describe('Banner Consent API — Edge Cases & Validation', () => {
  test('should return has_consent=false for unknown device', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent?site_id=nonexistent&device_fingerprint=unknown`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.has_consent).toBe(false)
  })

  test('should return default config for unconfigured site', async ({ request }) => {
    const res = await request.get(`${API_BASE}/banner/config/nonexistent-site`, {
      headers: HEADERS,
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body.site_id).toBe('nonexistent-site')
    expect(body.banner_title).toBe('Cookie-Einstellungen')
    expect(body.categories).toEqual([])
  })

  test('should reject invalid email for link-email', async ({ request }) => {
    const res = await request.post(`${API_BASE}/banner/consent/link-email`, {
      headers: HEADERS,
      data: {
        site_id: 'test',
        device_fingerprint: 'test',
        email: 'not-an-email',
      },
    })
    // Should fail — either 400 or 404 (no consent found)
    expect(res.status()).toBeGreaterThanOrEqual(400)
  })

  test('should return empty list for unknown email in by-email', async ({ request }) => {
    const res = await request.get(
      `${API_BASE}/banner/consent/by-email/nobody@nowhere.test`,
      { headers: HEADERS },
    )
    expect(res.ok()).toBeTruthy()
    const body = await res.json()
    expect(body).toEqual([])
  })

  test('should hash IP address (never store plain IP)', async ({ request }) => {
    const siteId = `e2e-ip-test-${Date.now()}`
    const fp = `e2e-ip-fp-${Date.now()}`

    // Create site
    await request.post(`${API_BASE}/banner/admin/sites`, {
      headers: HEADERS,
      data: { site_id: siteId, site_name: 'IP Test' },
    })

    // Record consent with IP
    const res = await request.post(`${API_BASE}/banner/consent`, {
      headers: HEADERS,
      data: {
        site_id: siteId,
        device_fingerprint: fp,
        categories: ['necessary'],
        vendors: [],
        ip_address: '10.0.0.42',
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()

    // IP should be hashed, not stored plain
    expect(body.ip_hash).toBeTruthy()
    expect(body.ip_hash).not.toBe('10.0.0.42')
    expect(body.ip_hash.length).toBe(16) // SHA256[:16]

    // Cleanup
    await request.delete(`${API_BASE}/banner/consent/${body.id}`, { headers: HEADERS })
    await request.delete(`${API_BASE}/banner/admin/sites/${siteId}`, { headers: HEADERS })
  })
})


test.describe('Banner Consent API — Retention per Category', () => {
  const RET_SITE = `e2e-retention-${Date.now()}`

  test.beforeAll(async ({ request }) => {
    // Create site with categories and vendors
    await request.post(`${API_BASE}/banner/admin/sites`, {
      headers: HEADERS,
      data: { site_id: RET_SITE, site_name: 'Retention Test' },
    })
    await request.post(`${API_BASE}/banner/admin/sites/${RET_SITE}/categories`, {
      headers: HEADERS,
      data: { category_key: 'necessary', name_de: 'Notwendig', is_required: true },
    })
    await request.post(`${API_BASE}/banner/admin/sites/${RET_SITE}/categories`, {
      headers: HEADERS,
      data: { category_key: 'marketing', name_de: 'Marketing', is_required: false },
    })
    await request.post(`${API_BASE}/banner/admin/sites/${RET_SITE}/vendors`, {
      headers: HEADERS,
      data: { vendor_name: 'FB Pixel', category_key: 'marketing', retention_days: 90 },
    })
  })

  test('consent expiry should match max vendor retention', async ({ request }) => {
    const fp = `e2e-ret-fp-${Date.now()}`
    const res = await request.post(`${API_BASE}/banner/consent`, {
      headers: HEADERS,
      data: {
        site_id: RET_SITE,
        device_fingerprint: fp,
        categories: ['necessary', 'marketing'],
        vendors: ['FB Pixel'],
      },
    })
    expect(res.ok()).toBeTruthy()
    const body = await res.json()

    // Expiry should be based on max vendor retention (90 days for marketing)
    const expiresAt = new Date(body.expires_at)
    const createdAt = new Date(body.created_at)
    const diffDays = Math.round((expiresAt.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24))
    // Should be 90 days (marketing) not 365 (default)
    expect(diffDays).toBeGreaterThanOrEqual(89)
    expect(diffDays).toBeLessThanOrEqual(91)

    // Cleanup
    await request.delete(`${API_BASE}/banner/consent/${body.id}`, { headers: HEADERS })
  })

  test.afterAll(async ({ request }) => {
    await request.delete(`${API_BASE}/banner/admin/sites/${RET_SITE}`, {
      headers: HEADERS,
    })
  })
})
