import React, { useMemo, useState } from 'react';
import { ActivityIndicator, Modal, Platform, Pressable, Text, View } from 'react-native';
import { X } from 'lucide-react-native';
import { WebView } from 'react-native-webview';

import { editorShellStyles } from '../../features/editor/editorShellStyles';
import { themedColor } from '../../theme';
import { createArtifactNavigationGuard } from '../artifactPreviewUtils';
import { toolWidgetStyles } from '../primitives/toolWidgetStyles';

type FrameProps = {
  html: string;
  onFail: () => void;
  scrollEnabled: boolean;
};

/**
 * The sandboxed frame, mirroring the web's iframe posture (sandbox
 * `allow-scripts`, no `allow-same-origin`; see ArtifactInlineCard). The
 * sandbox invariants, as a set:
 * 1. The CSP baked into the html shell blocks programmatic egress
 *    (`connect-src 'none'`) — but only for THAT document, so
 * 2. the platform-aware navigation guard admits at most one document per
 *    WebView: on iOS the initial `source={{ html }}` load (reported as
 *    about:blank); on Android the initial load never consults the guard, so
 *    it denies every callback. Every artifact-initiated navigation, top or
 *    sub frame (http(s), data:, about:blank re-navs), is cancelled on both
 *    platforms, so artifact JS can never mint a replacement document
 *    without the CSP.
 * 3. `originWhitelist={['*']}` so every request reaches that guard —
 *    react-native-webview requires `['*']` for static HTML sources, and
 *    non-whitelisted URLs are NOT blocked, they are handed to the OS
 *    (`Linking.openURL`), which would itself be an escape.
 * 4. Popup windows are discarded natively (multiple windows ON, no
 *    `onOpenWindow`) and `window.open`/`target="_blank"` are frozen inside
 *    the document by the shell's POPUP_BLOCK.
 * 5. No shared state or device access: `incognito`, no DOM storage, no
 *    file/geolocation access.
 */
function ArtifactFrame(props: FrameProps) {
  // Remount per document: an artifact rewrite gets a fresh loading overlay
  // and a fresh navigation guard instead of stale ones from the previous html.
  return <ArtifactDocumentFrame key={props.html} {...props} />;
}

function ArtifactDocumentFrame({ html, onFail, scrollEnabled }: FrameProps) {
  const [loading, setLoading] = useState(true);
  // Fresh guard per WebView document (the keyed remount above pins one html
  // per mount; on iOS the initial document must be admitted again).
  const guardNavigation = useMemo(() => createArtifactNavigationGuard(Platform.OS), []);

  return (
    <View style={toolWidgetStyles.artifactFrameFill}>
      <WebView
        allowFileAccess={false}
        allowFileAccessFromFileURLs={false}
        allowUniversalAccessFromFileURLs={false}
        domStorageEnabled={false}
        geolocationEnabled={false}
        incognito
        javaScriptEnabled
        onError={onFail}
        onLoadEnd={() => setLoading(false)}
        onShouldStartLoadWithRequest={(request) => guardNavigation(request.url)}
        // '*' is the documented requirement for `source={{ html }}` documents
        // (and their subresources); the guard above is the real gate — see
        // invariant 3.
        originWhitelist={['*']}
        scrollEnabled={scrollEnabled}
        // Deliberately ON: with multiple windows DISABLED, Android loads
        // `target="_blank"` in the SAME WebView without invoking
        // onShouldStartLoadWithRequest (documented react-native-webview
        // bypass). Enabled with no onOpenWindow handler, popup requests are
        // discarded on both platforms; the shell's POPUP_BLOCK script
        // neutralizes window.open/_blank inside the document too.
        setSupportMultipleWindows
        source={{ html }}
        style={toolWidgetStyles.artifactWebView}
      />
      {loading ? (
        <View pointerEvents="none" style={toolWidgetStyles.artifactPreviewLoading}>
          <ActivityIndicator color={themedColor('#8E8E93')} />
        </View>
      ) : null}
    </View>
  );
}

/** Fixed-height inline preview for the artifact card body. */
export function ArtifactInlinePreview({ html, onFail }: { html: string; onFail: () => void }) {
  return (
    <View style={toolWidgetStyles.artifactPreviewBox}>
      <ArtifactFrame html={html} onFail={onFail} scrollEnabled={false} />
    </View>
  );
}

/** Full-screen viewer — same modal chrome as EditorDrawer (top bar + close). */
export function ArtifactFullscreenModal({
  html,
  onClose,
  onFail,
  title,
  visible,
}: {
  html: string;
  onClose: () => void;
  onFail: () => void;
  title: string;
  visible: boolean;
}) {
  return (
    <Modal animationType="slide" onRequestClose={onClose} presentationStyle="pageSheet" visible={visible}>
      <View style={editorShellStyles.modalRoot}>
        <View style={editorShellStyles.modalTopBar}>
          <Pressable
            accessibilityLabel="Close artifact"
            accessibilityRole="button"
            onPress={onClose}
            style={editorShellStyles.closeButton}
          >
            <X color={themedColor('#F4F4F5')} size={22} strokeWidth={2.5} />
          </Pressable>
          <View style={editorShellStyles.modalTitleWrap}>
            <Text numberOfLines={1} style={editorShellStyles.modalTitle}>{title}</Text>
          </View>
        </View>
        {visible ? <ArtifactFrame html={html} onFail={onFail} scrollEnabled /> : null}
      </View>
    </Modal>
  );
}
