"""§2 Feature Tour cells — 12 Security."""

from __future__ import annotations


def _md(*lines: str) -> dict:
    return {"cell_type": "markdown", "metadata": {}, "source": list(lines)}


def _code(tag: str, source: str) -> dict:
    return {
        "cell_type": "code",
        "metadata": {"tags": [tag]},
        "source": source.splitlines(keepends=True),
        "execution_count": None,
        "outputs": [],
    }


def section_cells_python() -> list[dict]:
    return [
        _md(
            "## §2 — Feature Tour\n\n"
            "Exercises webhook signature guards, URL classification, and the SSRF protection layer.\n"
        ),
        _md("### URL classification\n"),
        _code(
            "ft_url_classification",
            "from getpatter import is_remote_url, is_websocket_url\n"
            "with _setup.cell('url_classification', tier=1, env=env) as ok:\n"
            "    if ok:\n"
            "        cases = [\n"
            "            ('https://example.com/callback',  is_remote_url,    True,  'HTTPS URL'),\n"
            "            ('wss://api.example.com/stream',  is_remote_url,    True,  'WSS URL'),\n"
            "            ('wss://api.example.com/stream',  is_websocket_url, True,  'WSS is WebSocket'),\n"
            "            ('https://example.com/callback',  is_websocket_url, False, 'HTTPS is not WebSocket'),\n"
            "            (lambda msg: None,                is_remote_url,    False, 'callable is not URL'),\n"
            "        ]\n"
            '        print(f\'{"Function":<20s} {"Input type":<20s} {"Expected":<10s} {"Actual":<10s} {"OK"}\')\n'
            "        print('-' * 70)\n"
            "        for val, fn, expected, label in cases:\n"
            "            result = fn(val)\n"
            "            ok_mark = '✓' if result == expected else '✗'\n"
            "            print(f'{fn.__name__:<20s} {label:<20s} {str(expected):<10s} {str(result):<10s} {ok_mark}')\n"
            "            assert result == expected, f'{fn.__name__}({val!r}) expected {expected}, got {result}'\n",
        ),
        _md("### Twilio webhook guard: valid vs rejected signatures\n"),
        _code(
            "ft_twilio_sig_guard",
            "from twilio.request_validator import RequestValidator\n"
            "with _setup.cell('twilio_sig_guard', tier=1, env=env) as ok:\n"
            "    if ok:\n"
            "        auth_token = 'secret_auth_token_for_testing_only'\n"
            "        url        = 'https://example.com/webhook/voice'\n"
            "        params     = {'CallSid': 'CA0000000000000000000000000000a001', 'From': '+15555550100'}\n"
            "        validator  = RequestValidator(auth_token)\n"
            "\n"
            "        # Case 1: correct signature (generated by Twilio)\n"
            "        good_sig = validator.compute_signature(url, params)\n"
            "        assert validator.validate(url, params, good_sig), 'valid sig must pass'\n"
            "        print(f'✓ Valid signature accepted')\n"
            "\n"
            "        # Case 2: missing header (empty string)\n"
            "        assert not validator.validate(url, params, ''), 'empty sig must fail'\n"
            "        print(f'✓ Empty signature rejected')\n"
            "\n"
            "        # Case 3: wrong auth token\n"
            "        bad_validator = RequestValidator('wrong_token_xxxxxxxxxxxxxxxxxx')\n"
            "        assert not bad_validator.validate(url, params, good_sig), 'wrong token must fail'\n"
            "        print(f'✓ Wrong auth token rejected')\n"
            "\n"
            "        # Case 4: URL mismatch (SSRF-style redirect)\n"
            "        assert not validator.validate('https://evil.com/intercept', params, good_sig), 'URL mismatch must fail'\n"
            "        print(f'✓ URL mismatch rejected')\n",
        ),
        _md("### SSRF guard: private-IP rejection\n"),
        _code(
            "ft_ssrf_guard",
            "import ipaddress\n"
            "with _setup.cell('ssrf_guard', tier=1, env=env) as ok:\n"
            "    if ok:\n"
            "        def _is_ssrf_blocked(url: str) -> bool:\n"
            "            from urllib.parse import urlparse\n"
            "            parsed = urlparse(url)\n"
            "            hostname = parsed.hostname or ''\n"
            "            try:\n"
            "                addr = ipaddress.ip_address(hostname)\n"
            "                return addr.is_private or addr.is_loopback or addr.is_link_local or addr.is_reserved\n"
            "            except ValueError:\n"
            "                return False\n"
            "\n"
            "        cases = [\n"
            "            ('wss://api.example.com/ws',  False, 'public hostname'),\n"
            "            ('wss://127.0.0.1/ws',        True,  'loopback'),\n"
            "            ('wss://192.168.1.1/ws',      True,  'private LAN'),\n"
            "            ('wss://169.254.169.254/ws',  True,  'AWS metadata SSRF target'),\n"
            "            ('wss://10.0.0.1/ws',         True,  'RFC1918 private'),\n"
            "        ]\n"
            "        for url, expected_block, label in cases:\n"
            "            blocked = _is_ssrf_blocked(url)\n"
            "            mark = '✓' if blocked == expected_block else '✗'\n"
            "            action = 'BLOCKED' if blocked else 'allowed'\n"
            "            print(f'  {mark} {action:7s}  {label:30s}  {url}')\n"
            "            assert blocked == expected_block, f'SSRF check failed for {url}'\n",
        ),
        _md("### EventBus + observability\n"),
        _code(
            "ft_observability",
            "from getpatter import EventBus, is_tracing_enabled\n"
            "with _setup.cell('observability', tier=1, env=env) as ok:\n"
            "    if ok:\n"
            "        print(f'OTel tracing enabled: {is_tracing_enabled()}')\n"
            "        print('(Enable with getpatter.init_tracing() + OTEL_EXPORTER_OTLP_ENDPOINT)')\n"
            "\n"
            "        bus = EventBus()\n"
            "        log: list[str] = []\n"
            "\n"
            "        bus.on('call_ended',        lambda p: log.append(f'call_ended:{p[\"call_id\"]}'))\n"
            "        bus.on('transcript_final',  lambda p: log.append(f'transcript:{p.get(\"text\", \"\")[:20]}'))\n"
            "        bus.on('metrics_collected', lambda p: log.append(f'metrics:{p.get(\"call_id\", \"\")}'))\n"
            "\n"
            "        bus.emit('transcript_final',  {'text': 'Hello world', 'call_id': 'c1'})\n"
            "        bus.emit('metrics_collected', {'call_id': 'c1', 'cost': 0.05})\n"
            "        bus.emit('call_ended',        {'call_id': 'c1', 'duration': 45})\n"
            "\n"
            "        print(f'Event log:')\n"
            "        for entry in log:\n"
            "            print(f'  {entry}')\n"
            "        assert len(log) == 3\n",
        ),
    ]


def section_cells_typescript() -> list[dict]:
    return [
        _md(
            "## §2 — Feature Tour\n\n"
            "Exercises webhook signature guards, URL classification, and SSRF protection.\n"
        ),
        _md("### URL classification\n"),
        _code(
            "ft_url_classification",
            'import { isRemoteUrl, isWebsocketUrl } from "getpatter";\n'
            "await cell('url_classification', { tier: 1, env }, () => {\n"
            "  const cases: [any, (v: any) => boolean, boolean, string][] = [\n"
            "    ['https://example.com/cb',  isRemoteUrl,    true,  'HTTPS URL'],\n"
            "    ['wss://example.com/ws',    isRemoteUrl,    true,  'WSS URL'],\n"
            "    ['wss://example.com/ws',    isWebsocketUrl, true,  'WSS is WebSocket'],\n"
            "    ['https://example.com',     isWebsocketUrl, false, 'HTTPS not WebSocket'],\n"
            "    [() => {},                  isRemoteUrl,    false, 'callable not URL'],\n"
            "  ];\n"
            "  for (const [val, fn, expected, label] of cases) {\n"
            "    const result = fn(val);\n"
            "    const ok = result === expected ? '✓' : '✗';\n"
            "    console.log(`  ${ok} ${fn.name}  ${label}: ${result}`);\n"
            "    if (result !== expected) throw new Error(`${fn.name}(${label}) expected ${expected}`);\n"
            "  }\n"
            "});\n",
        ),
        _md("### Twilio webhook guard: valid vs rejected signatures\n"),
        _code(
            "ft_twilio_sig_guard",
            "import crypto from 'crypto';\n"
            "await cell('twilio_sig_guard', { tier: 1, env }, () => {\n"
            "  function computeSig(token: string, url: string, params: Record<string, string>): string {\n"
            "    const sorted = Object.keys(params).sort().map(k => k + params[k]).join('');\n"
            "    return crypto.createHmac('sha1', token).update(url + sorted).digest('base64');\n"
            "  }\n"
            "  const token  = 'secret_auth_token_for_testing_only';\n"
            "  const url    = 'https://example.com/webhook/voice';\n"
            "  const params = { CallSid: 'CA0000000000000000000000000000a001', From: '+15555550100' };\n"
            "  const good   = computeSig(token, url, params);\n"
            "  console.log('✓ Valid signature accepted');\n"
            "  const bad    = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';\n"
            "  console.log(`✓ Empty/bad sig differs: ${good !== bad}`);\n"
            "  const wrong  = computeSig('wrong_token_xxxxxxxxxxxxxxxxxx', url, params);\n"
            "  console.log(`✓ Wrong token differs: ${good !== wrong}`);\n"
            "  const evil   = computeSig(token, 'https://evil.com/intercept', params);\n"
            "  console.log(`✓ URL mismatch differs: ${good !== evil}`);\n"
            "  if (good === bad || good === wrong || good === evil) throw new Error('guard check failed');\n"
            "});\n",
        ),
        _md("### SSRF guard: private-IP rejection\n"),
        _code(
            "ft_ssrf_guard",
            "await cell('ssrf_guard', { tier: 1, env }, () => {\n"
            "  // Mirror the Python SSRF guard logic for demonstration.\n"
            "  function isPrivateIp(url: string): boolean {\n"
            "    try {\n"
            "      const host = new URL(url).hostname;\n"
            "      // Simple check for well-known private/loopback ranges.\n"
            "      return /^(127\\.|10\\.|192\\.168\\.|172\\.(1[6-9]|2\\d|3[01])\\.|169\\.254\\.)/.test(host);\n"
            "    } catch { return false; }\n"
            "  }\n"
            "  const cases: [string, boolean][] = [\n"
            "    ['wss://api.example.com/ws',  false],\n"
            "    ['wss://127.0.0.1/ws',        true],\n"
            "    ['wss://192.168.1.1/ws',      true],\n"
            "    ['wss://169.254.169.254/ws',  true],\n"
            "  ];\n"
            "  for (const [url, expected] of cases) {\n"
            "    const blocked = isPrivateIp(url);\n"
            "    console.log(`  ${blocked === expected ? '✓' : '✗'} ${blocked ? 'BLOCKED' : 'allowed'}: ${url}`);\n"
            "  }\n"
            "});\n",
        ),
        _md("### EventBus + observability\n"),
        _code(
            "ft_observability",
            'import { EventBus, isTracingEnabled } from "getpatter";\n'
            "await cell('observability', { tier: 1, env }, () => {\n"
            "  console.log(`OTel tracing: ${isTracingEnabled()}`);\n"
            "  const bus = new EventBus();\n"
            "  const log: string[] = [];\n"
            "  bus.on('call_ended',       (p: any) => log.push(`call_ended:${p.callId}`));\n"
            "  bus.on('transcript_final', (p: any) => log.push(`transcript:${p.text?.slice(0,20)}`));\n"
            "  bus.emit('transcript_final', { text: 'Hello world', callId: 'c1' });\n"
            "  bus.emit('call_ended',       { callId: 'c1', duration: 45 });\n"
            "  log.forEach(e => console.log(`  ${e}`));\n"
            "  if (log.length !== 2) throw new Error('expected 2 log entries');\n"
            "});\n",
        ),
    ]
