/**
 * Client-side Sentry initialization.
 *
 * Loaded dynamically only when SENTRY_DSN is available in the public env.
 * Import this module in your client entry-point or in a <script> tag that
 * ships only when the DSN is set.
 *
 * Usage (in an Astro layout — server injects DSN via runtime env, not PUBLIC_*):
 *
 *   {env?.SENTRY_DSN && (
 *     <script is:inline set:html={`window.__SENTRY_DSN__=${JSON.stringify(env.SENTRY_DSN)};window.__SENTRY_ENV__=${JSON.stringify(env.ENVIRONMENT ?? 'production')};`} />
 *   )}
 *   <script>
 *     const w = window;
 *     if (w.__SENTRY_DSN__) {
 *       import('../lib/sentry-client')
 *         .then((m) => m.initSentryClient(w.__SENTRY_DSN__, w.__SENTRY_ENV__))
 *         .catch(() => {});
 *     }
 *   </script>
 *
 * NOTE: The DSN itself is not secret - it is safe to embed in client bundles.
 * However we only do so when explicitly configured to avoid sending noise from
 * dev environments.
 */

import * as Sentry from '@sentry/astro';

/** PII deny-list - mirrors the server-side scrubber in sentry.ts */
const PII_KEYS = new Set([
  'phone',
  'email',
  'address',
  'display_name',
  'displayName',
  'ip',
  'ipAddress',
  'ip_address',
  'full_address',
  'fullAddress',
  'guest_email',
  'guest_phone',
  'name',
  'full_name',
  'fullName',
]);

const PII_VALUE_PATTERNS: RegExp[] = [
  /(?:\+972|0)[\s-]?(?:5[0-9]|[23489])[\s-]?\d{3}[\s-]?\d{4}/g,
  /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
];

function scrubStringValue(value: string): string {
  let result = value;
  for (const pattern of PII_VALUE_PATTERNS) {
    result = result.replace(pattern, '[Scrubbed]');
  }
  return result;
}

function scrubPii(obj: unknown, depth = 0): unknown {
  if (depth > 10) return obj;
  if (obj === null || typeof obj !== 'object') {
    if (typeof obj === 'string') return scrubStringValue(obj);
    return obj;
  }
  if (Array.isArray(obj)) return obj.map((item) => scrubPii(item, depth + 1));
  const result: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
    result[key] = PII_KEYS.has(key) ? '[Scrubbed]' : scrubPii(value, depth + 1);
  }
  return result;
}

let clientInitialized = false;

/**
 * Initialize Sentry on the client side.
 * Safe to call multiple times - only initializes once.
 */
export function initSentryClient(dsn: string, environment = 'production'): void {
  if (clientInitialized || !dsn) return;
  clientInitialized = true;

  Sentry.init({
    dsn,
    environment,
    tracesSampleRate: 0.1,
    // Replay disabled by default - enable if needed for specific debugging
    replaysSessionSampleRate: 0,
    replaysOnErrorSampleRate: 0,
    beforeSend(event) {
      if (event.user) {
        event.user = scrubPii(event.user) as typeof event.user;
        if (event.user?.ip_address) {
          event.user.ip_address = '[Scrubbed]';
        }
      }
      if (event.extra) {
        event.extra = scrubPii(event.extra) as typeof event.extra;
      }
      // In Sentry v8, event.breadcrumbs is Breadcrumb[] directly
      if (event.breadcrumbs) {
        event.breadcrumbs = event.breadcrumbs.map((crumb) => ({
          ...crumb,
          message: crumb.message ? scrubStringValue(crumb.message) : crumb.message,
          data: crumb.data ? (scrubPii(crumb.data) as Record<string, unknown>) : crumb.data,
        }));
      }
      return event;
    },
  });
}
