'use client'

/**
 * CookieResultView — strukturierte Cookie-/Vendor-Auswertung aus einem
 * gespeicherten Snapshot (cmp_vendors), OHNE Re-Crawl.
 *
 * Zwei Sichten (Umschalter):
 *  - Rechtliche Rolle: Eigene / Auftragsverarbeiter / Joint Controller (VVT)
 *  - Banner-Kategorie: Notwendig / Funktional / Statistik / Marketing — die im
 *    Consent-Banner implementierte Einteilung. Pro Cookie wird die tatsächliche
 *    Kategorie laut Library gegengeprüft → '→ sollte: Marketing' bei
 *    Fehl-Einsortierung (Tracker als notwendig = § 25 TDDDG-relevant).
 */

import React, { useMemo, useState } from 'react'

export interface SnapshotCookie {
  name: string
  expiry?: string
  purpose?: string
  is_third_party?: boolean
  functional_role?: string
}

export interface SnapshotVendor {
  name: string
  cookies?: SnapshotCookie[]
  category?: string
  country?: string
  recipient_type?: string
  compliance_score?: number
  compliance_flags?: string[]
  opt_out_ok?: boolean
}

interface Snapshot {
  id: string
  site_domain?: string
  created_at?: string
  cmp_vendors?: SnapshotVendor[]
}

// name_lower → tatsächliche Kategorie laut Library (aus /cookie-check).
export type LibCategories = Record<string, string>
// name_lower → Speichertyp (cookie | local_storage | framework_storage | …).
export type StorageTypes = Record<string, string>

const STORAGE_LABEL: Record<string, string> = {
  cookie: 'Cookie', local_storage: 'Local Storage',
  session_storage: 'Session Storage', indexeddb: 'IndexedDB',
  framework_storage: 'Framework',
}
const STORAGE_COLOR: Record<string, string> = {
  cookie: 'bg-gray-100 text-gray-500',
  local_storage: 'bg-purple-100 text-purple-700',
  session_storage: 'bg-indigo-100 text-indigo-700',
  indexeddb: 'bg-cyan-100 text-cyan-700',
  framework_storage: 'bg-orange-100 text-orange-700',
}
const STORAGE_ORDER = ['cookie', 'local_storage', 'session_storage', 'indexeddb', 'framework_storage']

function storageOf(name: string, st?: StorageTypes): string {
  return st?.[(name || '').toLowerCase()] || 'cookie'
}

const ROLE_LABEL: Record<string, string> = {
  unknown: 'Unbekannt', ad_pixel: 'Werbe-Pixel', auth_token: 'Auth-Token',
  preference: 'Präferenz', visitor_id: 'Besucher-ID', consent_state: 'Consent',
  tracking: 'Tracking',
}
const CAT_COLOR: Record<string, string> = {
  necessary: 'bg-green-100 text-green-700', functional: 'bg-blue-100 text-blue-700',
  statistics: 'bg-amber-100 text-amber-700', marketing: 'bg-red-100 text-red-700',
}
const EEA = new Set([
  'DE','FR','IE','NL','AT','BE','BG','HR','CY','CZ','DK','EE','FI','GR','HU',
  'IT','LV','LT','LU','MT','PL','PT','RO','SK','SI','ES','SE','IS','LI','NO',
])
const GROUPS = [
  { key: 'own', label: 'Eigene Verarbeitungen (VVT, Art. 30)', test: (r: string) => !r || r === 'INTERNAL' || r === 'GROUP' },
  { key: 'proc', label: 'Auftragsverarbeiter (AVV, Art. 28)', test: (r: string) => r === 'PROCESSOR' },
  { key: 'joint', label: 'Eigenverantwortliche Dritte / Joint Controller (Art. 26)', test: (r: string) => r === 'JOINT_CONTROLLER' || r === 'CONTROLLER' },
  { key: 'other', label: 'Sonstige Empfänger', test: () => true },
]

// Banner-Kategorie-Sicht: kanonische Buckets + Labels.
const CAT_CANON: Record<string, string> = {
  necessary: 'necessary', essential: 'necessary', notwendig: 'necessary',
  essenziell: 'necessary', security: 'necessary', 'strictly necessary': 'necessary',
  functional: 'functional', funktional: 'functional', preferences: 'functional',
  preference: 'functional', präferenzen: 'functional',
  statistics: 'statistics', statistik: 'statistics', analytics: 'statistics',
  performance: 'statistics',
  marketing: 'marketing', targeting: 'marketing', advertising: 'marketing',
  werbung: 'marketing', social_media: 'marketing', social: 'marketing', ad: 'marketing',
}
const CANON_LABEL: Record<string, string> = {
  necessary: 'Notwendig', functional: 'Funktional',
  statistics: 'Statistik', marketing: 'Marketing', unknown: '—',
}
const CATEGORY_GROUPS = [
  { key: 'necessary', label: 'Notwendig (essenziell)' },
  { key: 'functional', label: 'Funktional' },
  { key: 'statistics', label: 'Statistik' },
  { key: 'marketing', label: 'Marketing' },
  { key: 'unknown', label: 'Ohne Kategorie' },
]

function canonCat(c?: string): string {
  return CAT_CANON[(c || '').toLowerCase().trim()] || 'unknown'
}

// Tatsächliche Kategorie laut Library vs. deklarierte Banner-Kategorie.
function mismatch(name: string, declaredCanon: string, lib?: LibCategories) {
  const raw = lib?.[name.toLowerCase()]
  if (!raw) return null
  const actual = canonCat(raw)
  if (actual === 'unknown' || actual === declaredCanon) return null
  // severe: als notwendig deklariert, laut Library einwilligungspflichtig.
  const severe = declaredCanon === 'necessary'
    && (actual === 'marketing' || actual === 'statistics')
  return { actual, severe }
}

function scoreColor(s?: number): string {
  if (s == null) return 'text-gray-400'
  return s >= 80 ? 'text-green-700' : s >= 50 ? 'text-amber-700' : 'text-red-700'
}

function Tile({ label, value, tone }: { label: string; value: React.ReactNode; tone: string }) {
  return (
    <div className="border border-gray-200 rounded-lg p-3 bg-white">
      <div className={`text-2xl font-semibold leading-none ${tone}`}>{value}</div>
      <div className="text-xs text-gray-500 mt-1.5">{label}</div>
    </div>
  )
}

function VendorRow(
  { v, lib, st, sf }:
  { v: SnapshotVendor; lib?: LibCategories; st?: StorageTypes; sf: string },
) {
  const [open, setOpen] = useState(false)
  const cookies = sf
    ? (v.cookies || []).filter(c => storageOf(c.name, st) === sf)
    : (v.cookies || [])
  const cat = (v.category || '').toLowerCase()
  const declaredCanon = canonCat(v.category)
  const drittland = !!v.country && !EEA.has((v.country || '').toUpperCase())
  return (
    <div>
      <button
        onClick={() => setOpen(o => !o)}
        className="w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-gray-50 text-xs"
      >
        <span className={`text-gray-400 transition-transform ${open ? 'rotate-90' : ''}`}>›</span>
        <span className="font-medium text-gray-800 flex-1 min-w-0 truncate">{v.name}</span>
        {cat && (
          <span className={`px-1.5 py-0.5 rounded text-[10px] ${CAT_COLOR[cat] || 'bg-gray-100 text-gray-600'}`}>
            {v.category}
          </span>
        )}
        {drittland && (
          <span className="px-1.5 py-0.5 rounded text-[10px] bg-red-50 text-red-600" title="außerhalb EWR">
            {v.country}
          </span>
        )}
        <span className="text-gray-500 w-12 text-right" title="Cookies">{cookies.length}</span>
        <span className={`w-10 text-right font-semibold ${scoreColor(v.compliance_score)}`}>
          {v.compliance_score != null ? `${v.compliance_score}%` : '—'}
        </span>
      </button>
      {open && cookies.length > 0 && (
        <div className="ml-6 mb-1 border-l-2 border-gray-200">
          <table className="w-full text-[11px]">
            <thead className="text-gray-400">
              <tr>
                <th className="px-2 py-1 text-left font-normal">Cookie</th>
                <th className="px-2 py-1 text-left font-normal">Speicher</th>
                <th className="px-2 py-1 text-left font-normal">Rolle</th>
                <th className="px-2 py-1 text-left font-normal">Zweck</th>
                <th className="px-2 py-1 text-left font-normal">Laufzeit</th>
              </tr>
            </thead>
            <tbody>
              {cookies.map((c, i) => {
                const mm = mismatch(c.name, declaredCanon, lib)
                return (
                  <tr key={i} className="border-t border-gray-100 align-top">
                    <td className="px-2 py-1 font-mono text-gray-700 break-all w-40">
                      {c.name}
                      {mm && (
                        <span
                          className={`ml-1 inline-block px-1 py-0.5 rounded text-[9px] font-sans ${mm.severe ? 'bg-red-100 text-red-700' : 'bg-amber-100 text-amber-700'}`}
                          title="tatsächliche Kategorie laut Library"
                        >
                          → sollte: {CANON_LABEL[mm.actual]}
                        </span>
                      )}
                    </td>
                    <td className="px-2 py-1 w-24">
                      {(() => {
                        const t = storageOf(c.name, st)
                        return t !== 'cookie' ? (
                          <span className={`px-1 py-0.5 rounded text-[9px] ${STORAGE_COLOR[t]}`}>
                            {STORAGE_LABEL[t] || t}
                          </span>
                        ) : <span className="text-gray-300 text-[10px]">Cookie</span>
                      })()}
                    </td>
                    <td className="px-2 py-1 text-gray-500 w-24">
                      {c.functional_role && c.functional_role !== 'unknown'
                        ? (ROLE_LABEL[c.functional_role] || c.functional_role)
                        : <span className="text-gray-300">—</span>}
                    </td>
                    <td className="px-2 py-1 text-gray-500 break-words">
                      {c.purpose
                        ? c.purpose
                        : <span className="text-amber-600 italic">kein Zweck</span>}
                    </td>
                    <td className="px-2 py-1 text-gray-400 w-24 whitespace-nowrap">{c.expiry || '—'}</td>
                  </tr>
                )
              })}
            </tbody>
          </table>
        </div>
      )}
    </div>
  )
}

export function CookieResultView(
  { snapshot, cookieCategories, storageTypes }:
  { snapshot: Snapshot; cookieCategories?: LibCategories; storageTypes?: StorageTypes },
) {
  const vendors = snapshot.cmp_vendors || []
  const [viewMode, setViewMode] = useState<'role' | 'category'>('role')
  const [storageFilter, setStorageFilter] = useState('')

  // Speichertyp-Verteilung über alle Cookies (für die Filter-Chips + Zähler).
  const storagePresent = useMemo(() => {
    const counts: Record<string, number> = {}
    for (const v of vendors)
      for (const c of v.cookies || []) {
        const t = storageOf(c.name, storageTypes)
        counts[t] = (counts[t] || 0) + 1
      }
    return counts
  }, [vendors, storageTypes])

  const matchesSF = (v: SnapshotVendor) =>
    !storageFilter || (v.cookies || []).some(c => storageOf(c.name, storageTypes) === storageFilter)

  const stats = useMemo(() => {
    const cookies = vendors.reduce((n, v) => n + (v.cookies?.length || 0), 0)
    const marketing = vendors.filter(v => (v.category || '').toLowerCase() === 'marketing').length
    const drittland = vendors.filter(v => v.country && !EEA.has(v.country.toUpperCase())).length
    let misplaced = 0
    for (const v of vendors) {
      const dc = canonCat(v.category)
      for (const c of v.cookies || []) {
        if (mismatch(c.name, dc, cookieCategories)?.severe) misplaced++
      }
    }
    return { cookies, marketing, drittland, misplaced }
  }, [vendors, cookieCategories])

  const grouped = useMemo(() => {
    const sortByScore = (a: SnapshotVendor, b: SnapshotVendor) =>
      (a.compliance_score ?? 100) - (b.compliance_score ?? 100)
    if (viewMode === 'category') {
      return CATEGORY_GROUPS
        .map(g => ({ ...g, vendors: vendors.filter(v => canonCat(v.category) === g.key).filter(matchesSF).sort(sortByScore) }))
        .filter(g => g.vendors.length > 0)
    }
    return GROUPS
      .map(g => ({
        ...g,
        vendors: vendors
          .filter(v => GROUPS.find(gg => gg.test((v.recipient_type || '').toUpperCase()))?.key === g.key)
          .filter(matchesSF)
          .sort(sortByScore),
      }))
      .filter(g => g.vendors.length > 0)
  }, [vendors, viewMode, storageFilter, storageTypes])

  const toggleBtn = (mode: 'role' | 'category', label: string) => (
    <button
      onClick={() => setViewMode(mode)}
      className={`px-2.5 py-1 rounded text-xs ${viewMode === mode ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
    >
      {label}
    </button>
  )

  return (
    <div className="space-y-4">
      <div className="flex items-start justify-between gap-3 flex-wrap">
        <div>
          <h2 className="text-lg font-semibold text-gray-900">
            Cookie-Auswertung — {snapshot.site_domain || 'Snapshot'}
          </h2>
          <p className="text-xs text-gray-500 mt-0.5">
            aus gespeichertem Snapshot (kein Re-Crawl) ·{' '}
            {snapshot.created_at ? snapshot.created_at.slice(0, 19).replace('T', ' ') : ''}
          </p>
        </div>
        <div className="flex items-center gap-1">
          <span className="text-[11px] text-gray-500 mr-1">Gruppierung:</span>
          {toggleBtn('role', 'Rechtliche Rolle')}
          {toggleBtn('category', 'Banner-Kategorie')}
        </div>
      </div>

      <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3">
        <Tile label="Anbieter" value={vendors.length} tone="text-gray-800" />
        <Tile
          label={storageFilter ? `${STORAGE_LABEL[storageFilter] || storageFilter} (gefiltert)` : 'Cookies gesamt'}
          value={storageFilter ? (storagePresent[storageFilter] || 0) : stats.cookies}
          tone="text-gray-800"
        />
        <Tile label="Marketing-Anbieter" value={stats.marketing} tone={stats.marketing > 0 ? 'text-red-700' : 'text-gray-800'} />
        <Tile label="Drittland (außerhalb EWR)" value={stats.drittland} tone={stats.drittland > 0 ? 'text-amber-700' : 'text-gray-800'} />
        <Tile label="Falsch einsortiert (lt. Library)" value={stats.misplaced} tone={stats.misplaced > 0 ? 'text-red-700' : 'text-gray-800'} />
      </div>

      {Object.keys(storagePresent).filter(t => t !== 'cookie').length > 0 && (
        <div className="flex items-center gap-1 flex-wrap">
          <span className="text-[11px] text-gray-500 mr-1">Speichertyp:</span>
          <button
            onClick={() => setStorageFilter('')}
            className={`px-2 py-0.5 rounded text-[11px] ${!storageFilter ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
          >
            Alle ({stats.cookies})
          </button>
          {STORAGE_ORDER.filter(t => storagePresent[t]).map(t => (
            <button
              key={t}
              onClick={() => setStorageFilter(f => f === t ? '' : t)}
              className={`px-2 py-0.5 rounded text-[11px] ${storageFilter === t ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
            >
              {STORAGE_LABEL[t] || t} ({storagePresent[t]})
            </button>
          ))}
        </div>
      )}

      {viewMode === 'category' && (
        <p className="text-[11px] text-gray-500 -mt-1">
          Banner-Kategorie wie im Consent-Tool deklariert. Badge{' '}
          <span className="px-1 py-0.5 rounded text-[9px] bg-red-100 text-red-700">→ sollte: …</span>{' '}
          zeigt die tatsächliche Kategorie laut Library (Fehl-Einsortierung).
        </p>
      )}

      {grouped.map(g => (
        <div key={g.key} className="border rounded-lg overflow-hidden">
          <div className="px-3 py-2 bg-slate-50 border-b text-xs font-semibold text-gray-700">
            {g.label} <span className="text-gray-400 font-normal">({g.vendors.length})</span>
          </div>
          <div className="divide-y divide-gray-100">
            {g.vendors.map((v, i) => <VendorRow key={i} v={v} lib={cookieCategories} st={storageTypes} sf={storageFilter} />)}
          </div>
        </div>
      ))}
    </div>
  )
}
