/**
 * Unified event catalog shared between frontend (GA4/PostHog) and backend (EventCatalog.php).
 *
 * Naming convention: domain_action (snake_case).
 * Backend EventCatalog.php mirrors these values. AnalyticsEventService adds 'analytics.' prefix at dispatch.
 *
 * Annotation guide (explains why many exports have zero TypeScript import references):
 *   @server-only   — dispatched exclusively from PHP (AnalyticsEventService); never imported by TypeScript files by design.
 *   @server-mirror — currently frontend-dispatched; a matching server-side dispatch should also be added
 *                    (see comment for target controller). Both sides track the same event.
 *   (none)         — confirmed frontend-dispatched. Active TypeScript imports verified.
 *   @pending       — defined but not yet dispatched from the frontend. Needs implementation or explicit
 *                    reclassification as @server-only. Auditable via: grep -c '@pending' event-catalog.ts
 *   @deprecated    — no longer emitted; preserved for LEGACY_EVENT_MAP backward-compatibility only.
 *
 * Coverage: ~76 of ~184 exports are actively imported by TypeScript files. The remaining exports are
 * either @server-only (zero TS imports by design), @deprecated aliases, or @pending (awaiting frontend
 * instrumentation — see individual annotations).
 */

// ── Onboarding ──────────────────────────────────────────────────────────────
// Canonical per-step view event — fires for each individual wizard step (multiple per session).
// For funnel-stage counts (wizard entered), use ONBOARDING_WIZARD_VIEWED instead.
export const ONBOARDING_STEP_VIEWED = 'onboarding_step_viewed';
/** @server-only Dispatched by OnboardingProgressService when an individual onboarding step is completed. Carries `step` and `completed_steps` properties. Distinct from ONBOARDING_COMPLETED which fires once on wizard completion. */
export const ONBOARDING_STEP_COMPLETED = 'onboarding_step_completed';
export const ONBOARDING_ABANDONED = 'onboarding_abandoned';
// Canonical wizard-completion event — emitted in OnboardingWizard on final step.
export const ONBOARDING_COMPLETED = 'onboarding_completed';
/** Fired when user explicitly clicks "Explore with sample data" CTA in the onboarding wizard (ACT-003). */
export const DEMO_MODE_ENTERED = 'demo_mode_entered';
/** @pending Fired when user clicks an action on the setup card widget. Needs dispatch site. */
export const SETUP_CARD_ACTION_CLICKED = 'setup_card_action_clicked';
export const WIZARD_AI_STEP_SHOWN = 'wizard_ai_step_shown';
/** @pending Fired when the BYOK teaser panel is displayed in the wizard. Needs dispatch site. */
export const BYOK_TEASER_SHOWN = 'byok_teaser_shown';
/** Fired when user clicks "Remind me later" on the BYOK nudge card in the onboarding wizard. */
export const BYOK_NUDGE_DEFERRED = 'byok_nudge_deferred';
export const REFERRAL_CTA_SHOWN = 'referral_cta_shown';
export const REFERRAL_LINK_COPIED = 'referral_link_copied';
export const TEAM_INVITE_SENT = 'team_invite_sent';
/** Fired when user clicks "See Your Recommendations" CTA in the onboarding wizard after analysis completes (ACT-007). */
export const WIZARD_SEE_RECOMMENDATIONS_CLICKED = 'wizard_see_recommendations_clicked';
/** @server-only Fired when a team invite is accepted (invitee clicks the accept link and joins the site). Dispatched via AnalyticsEventService. */
export const TEAM_INVITE_ACCEPTED = 'team_invite_accepted';
/** @server-only Fired when a team member is removed from a site. Dispatched via AnalyticsEventService. */
export const TEAM_MEMBER_REMOVED = 'team_member_removed';
/** @server-only Fired when a team member's role is changed on a site. Dispatched via AnalyticsEventService. */
export const TEAM_ROLE_CHANGED = 'team_role_changed';
/** @server-only Fired when a site is shared with another user (team invite flow initiated). Dispatched via AnalyticsEventService. */
export const SITE_SHARED = 'site_shared';
export const RECOMMENDATIONS_FIRST_VIEWED = 'recommendations_first_viewed';

// ── Dashboard ───────────────────────────────────────────────────────────────
/** Fired when the main dashboard is viewed. */
export const DASHBOARD_VIEWED = 'dashboard_viewed';

/** Properties for DASHBOARD_VIEWED events. */
export interface DashboardViewedProps {
  /**
   * Site identifier as a string. PostHog and the event warehouse treat site_id
   * as a string dimension — do NOT send as a number or joins will type-mismatch.
   */
  site_id: string;
  /** Number of sites the user has. */
  site_count: number;
  /** Current subscription tier key (e.g. 'free', 'pro', 'team'). */
  plan_tier: string;
  /** Index signature required to satisfy Record<string, string | number | boolean> constraint. */
  [key: string]: string | number | boolean;
}
/** Fired when the setup checklist card is dismissed by the user. */
export const SETUP_CHECKLIST_DISMISSED = 'setup_checklist_dismissed';
/** Fired when a onboarding or product milestone is celebrated (confetti/toast). */
export const MILESTONE_CELEBRATED = 'milestone_celebrated';

// ── Analysis ────────────────────────────────────────────────────────────────
/** @pending Fired when the analysis page is viewed. Needs dispatch in Analyze/Index.tsx. */
export const ANALYSIS_PAGE_VIEWED = 'analysis_page_viewed';
export const ANALYSIS_INITIATED = 'analysis_initiated';

// ── Recommendations ─────────────────────────────────────────────────────────
export const RECOMMENDATIONS_VIEWED = 'recommendations_viewed';
/** @pending Fired when user expands a recommendation card to see its full detail. Needs dispatch in RecommendationCard.tsx expand handler. */
export const RECOMMENDATION_EXPANDED = 'recommendation_expanded';
export const RECOMMENDATION_DETAIL_VIEWED = 'recommendation_detail_viewed';
export const RECOMMENDATION_APPLIED = 'recommendation_applied';
export const RECOMMENDATION_STATUS_CHANGED = 'recommendation_status_changed';
/** @pending Fired when user opens the AI draft preview modal on a recommendation. Needs dispatch in DraftPreview.tsx or the button that opens it. */
export const DRAFT_PREVIEW_OPENED = 'draft_preview_opened';
export const DRAFT_PUBLISHED = 'draft_published';
/** @server-only Fired when the WordPress webhook confirms successful publication (distinct from DRAFT_PUBLISHED which fires on request). */
export const WP_PUBLISH_CONFIRMED = 'wp_publish_confirmed';
export const DRAFT_VIEWED = 'draft_viewed';

// ── AI Jobs ────────────────────────────────────────────────────────────────
export const GENERATE_DRAFT_CLICKED = 'generate_draft_clicked';
export const AI_JOB_VIEWED = 'ai_job_viewed';

// ── Content Editor ──────────────────────────────────────────────────────────
// All content-editor lifecycle events belong here regardless of how they were
// discovered (e.g. CONTENT_EDITOR_OPENED was previously filed under Features).
export const CONTENT_EDITOR_OPENED = 'content_editor_opened';
export const EDITOR_SESSION_START = 'editor_session_start';
export const EDITOR_SCORE_CHANGED = 'editor_score_changed';
export const EDITOR_SERP_PANEL_VIEWED = 'editor_serp_panel_viewed';
export const EDITOR_SESSION_END = 'editor_session_end';

/** Properties for EDITOR_SESSION_START events. */
export interface EditorSessionStartProps {
  /**
   * Unique identifier for this editor session. Generate once on mount (e.g. `crypto.randomUUID()`).
   * Must match the `session_id` sent in the corresponding EDITOR_SESSION_END event so
   * analytics tools can correlate start and end without manual event-pair joins.
   */
  session_id: string;
  /** Site identifier (string form of the numeric site ID). */
  site_id: string;
  /** Draft identifier being edited. */
  draft_id: number;
}

/** Properties for EDITOR_SESSION_END events. */
export interface EditorSessionEndProps {
  /**
   * Unique identifier matching the `session_id` from the corresponding EDITOR_SESSION_START event.
   * Generate once on mount with `crypto.randomUUID()`.
   */
  session_id: string;
  /** Draft identifier being edited. */
  draft_id: number;
  /** Session duration in milliseconds, calculated client-side as `Date.now() - startTimestamp`. */
  duration_ms: number;
  /** Content score at the time the session ended (0 if no score was computed). */
  final_score: number;
  /** Whether the user initiated a publish action during this editor session. */
  published: boolean;
  /** Whether a SERP analysis was triggered at least once during this session. */
  serp_analysis_triggered: boolean;
}

// ── ROI ─────────────────────────────────────────────────────────────────────
export const ROI_DASHBOARD_VIEWED = 'roi_dashboard_viewed';

// ── Filters ─────────────────────────────────────────────────────────────────
export const FILTER_APPLIED = 'filter_applied';
// FILTER_USED is server-only — use PHP `EventCatalog::FILTER_USED`.
// Do NOT add a client-side export; the authoritative definition lives in EventCatalog.php.
/** Fired when the user submits a search query on a list or table page. */
export const SEARCH_PERFORMED = 'search_performed';
/** Fired when the user changes the sort column or direction on a list or table page. */
export const SORT_CHANGED = 'sort_changed';

/** Properties for SEARCH_PERFORMED events. */
export interface SearchPerformedProps {
  /**
   * SHA-256 hash of the raw search term (lowercase-trimmed before hashing).
   * Never send the raw term — it may contain PII (names, emails, domains).
   * Hash client-side: `await crypto.subtle.digest('SHA-256', new TextEncoder().encode(term.trim().toLowerCase()))`.
   */
  search_term_hash: string;
  /** Number of results returned for the search. */
  result_count: number;
  /** Identifier of the page where the search was performed (e.g. 'admin_users', 'admin_findings', 'recommendations'). */
  page_name: string;
}

/** Properties for SORT_CHANGED events. */
export interface SortChangedProps {
  /** The column or field being sorted (e.g. 'created_at', 'impact_score', 'email'). */
  sort_column: string;
  /** Sort direction after the change. */
  sort_direction: 'asc' | 'desc';
  /** Identifier of the page where the sort was changed. */
  page_name: string;
}

// ── Billing / Ecommerce ─────────────────────────────────────────────────────
/** @pending Fired when user initiates checkout (clicks upgrade/subscribe). Needs dispatch in Billing/Index.tsx or checkout redirect handler. */
export const BEGIN_CHECKOUT = 'begin_checkout';
/** @pending Fired on successful subscription purchase. Needs dispatch in checkout success handler (SubscriptionController or Billing/Index.tsx). */
export const PURCHASE = 'purchase';
/** @server-only User abandoned the checkout session (Stripe session expired). Dispatched via AnalyticsEventService. */
export const CHECKOUT_ABANDONED = 'checkout_abandoned';
/** @pending Checkout flow encountered a payment error (declined, SCA failure, etc.). Needs dispatch in payment_intent.payment_failed webhook handler or Stripe checkout return URL handler. */
export const CHECKOUT_ERROR = 'checkout_error';
/**
 * @server-only MRR changed due to upgrade, downgrade, churn, or reactivation.
 * Dispatched from StripeWebhookController on customer.subscription.updated/deleted.
 * Primary revenue health metric — tracked in PostHog for cohort MRR analysis.
 */
export const SUBSCRIPTION_MRR_CHANGED = 'subscription_mrr_changed';
/**
 * @server-only Trial converted to paid subscription.
 * Dispatched from StripeWebhookController when trial_end arrives and payment succeeds.
 */
export const TRIAL_CONVERTED = 'trial_converted';
/**
 * @server-only Trial ended without conversion (expired or cancelled during trial).
 * Dispatched from StripeWebhookController when trial ends without a paid subscription.
 */
export const TRIAL_CHURNED = 'trial_churned';

// ── Analytics Health ────────────────────────────────────────────────────────
export const ANALYTICS_HEALTH_CHECK_FAILED = 'analytics_health_check_failed';
export const CONSENT_DECISION = 'consent_decision';

// ── Onboarding (extended) ──────────────────────────────────────────────────
// Canonical funnel-stage event — fires once on wizard mount (use for funnel entry counts).
export const ONBOARDING_WIZARD_VIEWED = 'onboarding_wizard_viewed';
// @deprecated Not emitted. Canonical equivalent is ONBOARDING_COMPLETED.
export const ONBOARDING_WIZARD_COMPLETED = 'onboarding_wizard_completed';
export const ONBOARDING_RESUME_CLICKED = 'onboarding_resume_clicked';
export const GSC_SYNC_STARTED = 'gsc_sync_started';
export const GSC_SYNC_COMPLETED = 'gsc_sync_completed';
/** @server-only Dispatched when a GSC sync job fails after all retry attempts. */
export const GSC_SYNC_FAILED = 'gsc_sync_failed';
export const GSC_SYNC_WAIT_ABANDONED = 'gsc_sync_wait_abandoned';
/** Fired when user intentionally navigates away via the "Go to Dashboard" escape CTA during sync wait.
 * Distinct from ONBOARDING_ABANDONED (which fires on unmount without explicit action). */
export const GSC_SYNC_ESCAPE = 'gsc_sync_escape';
/** Properties for GSC_SYNC_FAILED events. */
export interface GscSyncFailedProps {
  /** Machine-readable error category (e.g. 'oauth_expired', 'rate_limited', 'network_error', 'quota_exceeded'). */
  error_type: string;
  /** Number of retry attempts made before the final failure. */
  retry_count: number;
}

export const GSC_CONNECT_CLICKED = 'gsc_connect_clicked';
export const GSC_CONNECT_INITIATED = 'gsc_connect_initiated';
export const WP_CONNECT_CLICKED = 'wp_connect_clicked';
export const WP_CONNECT_INITIATED = 'wp_connect_initiated';
export const WP_STEP_SKIPPED = 'wp_step_skipped';
export const WP_INSTALL_STARTED = 'wp_install_started';
export const WP_PLUGIN_DETECTED = 'wp_plugin_detected';
export const ANALYZE_NOW_CLICKED = 'analyze_now_clicked';

// ── Experiments ───────────────────────────────────────────────────────────
/** Fired when a user is exposed to an A/B experiment variant. Carries `experiment_key` and `variant` properties. */
export const EXPERIMENT_EXPOSURE = 'experiment_exposure';

// ── Marketing ──────────────────────────────────────────────────────────────
export const PAGE_VIEWED = 'page_viewed';
export const CTA_CLICKED = 'cta_clicked';
/** Fired when a user clicks a CTA on the Learn Hub page. */
export const HUB_CTA_CLICKED = 'hub_cta_clicked';
/** Fired when a user clicks a feature deep-link on the Learn Hub page. */
export const HUB_FEATURE_LINK_CLICKED = 'hub_feature_link_clicked';
/** Fired when a user clicks a blog post card on the Learn Hub page. */
export const HUB_POST_CLICKED = 'hub_post_clicked';
/** Fired when a user clicks a related guide on the Learn Hub page. */
export const HUB_RELATED_GUIDE_CLICKED = 'hub_related_guide_clicked';
export const SOCIAL_PROOF_SECTION_VIEWED = 'social_proof_section_viewed';
export const VIDEO_PLAYED = 'video_played';

// ── Auth ───────────────────────────────────────────────────────────────────
export const LOGIN_PAGE_VIEWED = 'login_page_viewed';
export const REGISTER_PAGE_VIEWED = 'register_page_viewed';
// Canonical name (no FUNNEL_ prefix — consistent with REGISTRATION_COMPLETED, USER_SIGNED_IN).
export const REGISTRATION_STARTED = 'funnel_registration_started';
// @deprecated Use REGISTRATION_STARTED — FUNNEL_ prefix was applied inconsistently.
// The GA4 event string is unchanged ('funnel_registration_started') so historical data is preserved.
export const FUNNEL_REGISTRATION_STARTED = REGISTRATION_STARTED;
export const REGISTRATION_COMPLETED = 'registration_completed';
export const USER_SIGNED_IN = 'user_signed_in';

// ── Sites ──────────────────────────────────────────────────────────────────
// Canonical name (no FUNNEL_ prefix — consistent with domain naming convention).
export const SITE_CREATED = 'funnel_site_created';
// @deprecated Use SITE_CREATED — FUNNEL_ prefix was applied inconsistently.
// The GA4 event string is unchanged ('funnel_site_created') so historical data is preserved.
export const FUNNEL_SITE_CREATED = SITE_CREATED;

// ── Features ───────────────────────────────────────────────────────────────
export const FEATURE_USED = 'feature_used';
export const OPPORTUNITY_MAP_VIEWED = 'opportunity_map_viewed';
export const CONTENT_INTELLIGENCE_VIEWED = 'content_intelligence_viewed';
export const BATCH_AI_QUEUED = 'batch_ai_queued';
export const CONTENT_BRIEF_CREATED = 'content_brief_created';
export const REPORT_GENERATED = 'report_generated';
export const CALENDAR_VIEWED = 'calendar_viewed';
export const CALENDAR_EVENT_CREATED = 'calendar_event_created';
export const CALENDAR_EVENT_COMPLETED = 'calendar_event_completed';
export const CALENDAR_EVENT_RESCHEDULED = 'calendar_event_rescheduled';
/** @server-only Dispatched by SendCalendarRemindersJob when a reminder is sent. */
export const CALENDAR_REMINDER_SENT = 'calendar_reminder_sent';
/** Frontend-only: dispatched when the user exports the calendar as an iCal (.ics) file. */
export const ICAL_EXPORTED = 'ical_exported';
export const SERP_ANALYSIS_TRIGGERED = 'serp_analysis_triggered';
/** Fired when the user views SERP results after an analysis completes in the content editor. */
export const SERP_RESULTS_VIEWED = 'serp_results_viewed';
/** Fired when the user expands or drills into a specific SERP competitor's content in the editor sidebar. */
export const SERP_COMPETITOR_COMPARED = 'serp_competitor_compared';
/** Fired when the user's content score increases (next score > previous score) during an editor session. */
export const CONTENT_SCORE_IMPROVED = 'content_score_improved';
export const BULK_PUBLISH_INITIATED = 'bulk_publish_initiated';
/** @server-only Dispatched by BatchAiService when a batch AI job completes (all drafts generated or failed). */
export const BATCH_AI_COMPLETED = 'batch_ai_completed';
/** @server-only Dispatched by BulkPublishService when a bulk publish operation completes (all drafts published or failed). */
export const BULK_PUBLISH_COMPLETED = 'bulk_publish_completed';
/** Properties for BATCH_AI_COMPLETED and BULK_PUBLISH_COMPLETED events. */
export interface BatchOperationCompletedProps {
  /** Total number of items in the batch operation. */
  item_count: number;
  /** Number of items that completed successfully. */
  success_count: number;
  /** Number of items that failed. */
  failure_count: number;
  /** Duration of the batch operation in milliseconds. */
  duration_ms: number;
}

// ── Retention ──────────────────────────────────────────────────────────────
/**
 * @server-only Dispatched by EngagementMetricsDailyJob for users who crossed the 30-day
 * activity threshold today. Enables PostHog day-30 cohort retention analysis with a
 * named returning event (replaces the anonymous MAU proxy in FunnelStageDefinition).
 */
export const USER_RETAINED_30D = 'user_retained_30d';

// ── Settings ───────────────────────────────────────────────────────────────
// Server-side mirrors are implemented in the corresponding controllers via
// AnalyticsEventService, ensuring feature-adoption metrics are accurate for
// users with ad blockers that block client-side analytics (TAXON-011 resolved).
/** @server-mirror settings_ai_key_viewed — dispatched from AiSettingsController::showAiSettings() */
export const SETTINGS_AI_KEY_VIEWED = 'settings_ai_key_viewed';
/** @server-mirror settings_branding_viewed — dispatched from BrandingSettingsController::show() */
export const SETTINGS_BRANDING_VIEWED = 'settings_branding_viewed';
/** @server-mirror settings_security_viewed — dispatched from TwoFactorController::index() */
export const SETTINGS_SECURITY_VIEWED = 'settings_security_viewed';
/** @server-mirror settings_notifications_viewed — dispatched from NotificationSettingsController::show() */
export const SETTINGS_NOTIFICATIONS_VIEWED = 'settings_notifications_viewed';
/** @server-mirror settings_webhooks_viewed — dispatched from WebhookPageController::__invoke() */
export const SETTINGS_WEBHOOKS_VIEWED = 'settings_webhooks_viewed';
/** @server-mirror settings_api_tokens_viewed — dispatched from ApiTokenPageController::__invoke() */
export const SETTINGS_API_TOKENS_VIEWED = 'settings_api_tokens_viewed';

// ── Branding / White-label ──────────────────────────────────────────────────
/** @server-only Fired when the user saves branding settings (company name, colors, remove_rankwiz_branding). Dispatched from BrandingController. */
export const BRANDING_CONFIGURED = 'branding_configured';
/** @server-only Fired when the user saves a custom domain in branding settings. Dispatched from BrandingController. */
export const CUSTOM_DOMAIN_SET = 'custom_domain_set';
/** @server-only Fired when the user uploads or replaces their branding logo. Dispatched from BrandingController. */
export const LOGO_UPLOADED = 'logo_uploaded';

// ── Webhooks ───────────────────────────────────────────────────────────────
/** @server-only Dispatched when an outgoing webhook is delivered successfully (2xx response). */
export const WEBHOOK_DELIVERED = 'webhook_delivered';
/** @server-only Dispatched when an outgoing webhook delivery fails (non-2xx or network error). */
export const WEBHOOK_FAILED = 'webhook_failed';

// ── API Tokens ──────────────────────────────────────────────────────────────
export const API_TOKEN_CREATED = 'api_token_created';
export const API_TOKEN_REVOKED = 'api_token_revoked';
export const API_TOKEN_USED = 'api_token_used';

// ── Two-Factor Authentication ───────────────────────────────────────────────
export const TWO_FACTOR_ENABLED = 'two_factor_enabled';
export const TWO_FACTOR_DISABLED = 'two_factor_disabled';
export const TWO_FACTOR_CHALLENGED = 'two_factor_challenged';
export const TWO_FACTOR_SUCCEEDED = 'two_factor_succeeded';

// ── Content Briefs ─────────────────────────────────────────────────────────
export const CONTENT_BRIEFS_VIEWED = 'content_briefs_viewed';
export const CONTENT_BRIEF_DETAIL_VIEWED = 'content_brief_detail_viewed';

// ── Feature Gate Teasers ───────────────────────────────────────────────────
/** Fired when a locked-feature teaser panel is shown to a free-tier user. */
export const FEATURE_GATE_TEASER_SHOWN = 'feature_gate_teaser_shown';
/** Fired when a free-tier user clicks the upgrade CTA on a locked-feature teaser panel. */
export const FEATURE_GATE_UPGRADE_CLICKED = 'feature_gate_upgrade_clicked';

// ── Traffic Alerts ─────────────────────────────────────────────────────────
export const TRAFFIC_ALERTS_VIEWED = 'traffic_alerts_viewed';
export const TRAFFIC_ALERT_DETAIL_VIEWED = 'traffic_alert_detail_viewed';
export const TRAFFIC_ALERT_ACKNOWLEDGED = 'traffic_alert_acknowledged';
export const TRAFFIC_ALERT_DISMISSED = 'traffic_alert_dismissed';

// ── Content Intelligence ───────────────────────────────────────────────────
/** Tracked on both frontend (Cannibalization/Index.tsx) and server (CannibalizationController::index()). */
export const CANNIBALIZATION_VIEWED = 'cannibalization_viewed';
/** Tracked on both frontend (ContentIntelligence/TopicClusters/Index.tsx) and server (TopicClusterController::index()). */
export const TOPIC_CLUSTERS_VIEWED = 'topic_clusters_viewed';
/** Tracked on both frontend (ContentIntelligence/Freshness/Index.tsx) and server (FreshnessController::index()). */
export const FRESHNESS_VIEWED = 'freshness_viewed';

// ── Content History ────────────────────────────────────────────────────────
export const CONTENT_SNAPSHOT_CREATED = 'content_snapshot_created';
export const CONTENT_ROLLBACK_COMPLETED = 'content_rollback_completed';

// ── Pipeline ────────────────────────────────────────────────────────────────
/** Fired on mount of the Content Pipeline kanban board. */
export const PIPELINE_VIEWED = 'pipeline_viewed';
/** Fired when the user clicks the action CTA on a pipeline card. */
export const PIPELINE_CARD_CLICKED = 'pipeline_card_clicked';

// ── Page Views (product pages) ────────────────────────────────────────────
export const DEVICE_ANALYSIS_VIEWED = 'device_analysis_viewed';
export const GEOGRAPHIC_ANALYSIS_VIEWED = 'geographic_analysis_viewed';
export const CONTENT_HISTORY_VIEWED = 'content_history_viewed';
export const PORTFOLIO_VIEWED = 'portfolio_viewed';
export const BATCH_AI_DETAIL_VIEWED = 'batch_ai_detail_viewed';
export const FRESHNESS_ANALYSIS_VIEWED = 'freshness_analysis_viewed';
export const TOPIC_CLUSTERS_DETAIL_VIEWED = 'topic_clusters_detail_viewed';
export const TEAM_MANAGEMENT_VIEWED = 'team_management_viewed';
export const CONTENT_INVENTORY_VIEWED = 'content_inventory_viewed';
export const SERP_SETTINGS_VIEWED = 'serp_settings_viewed';

// ── Pricing ──────────────────────────────────────────────────────────────
export const PRICING_VIEWED = 'pricing_viewed';

// ── Errors ─────────────────────────────────────────────────────────────────
/**
 * Generic error shown to the user.
 *
 * Required properties:
 *   - `error_category`: broad class of error (see ErrorCategory constants below)
 *   - `error_severity`: impact tier (see ErrorSeverity constants below)
 *   - `error_code`: machine-readable code, e.g. `'SITE_LIMIT_REACHED'`, `'GSC_OAUTH_FAILED'`
 *
 * Optional properties:
 *   - `error_message`: human-readable description (omit PII)
 *   - `context`: component or page where the error appeared
 */
export const ERROR_DISPLAYED = 'error_displayed';

/** Broad error classification bucket for ERROR_DISPLAYED. */
export const ErrorCategory = {
  /** Client-side form validation failure. */
  VALIDATION: 'validation',
  /** Server returned a 4xx or 5xx response. */
  SERVER: 'server',
  /** User lacks permission for the attempted action. */
  AUTH: 'auth',
  /** External API or third-party integration failure (GSC, OpenAI, Stripe, etc.). */
  INTEGRATION: 'integration',
  /** Browser/network connectivity issue. */
  NETWORK: 'network',
  /** Unexpected JavaScript runtime error. */
  RUNTIME: 'runtime',
} as const;
export type ErrorCategoryValue = (typeof ErrorCategory)[keyof typeof ErrorCategory];

/** Severity tier for ERROR_DISPLAYED — drives alert priority in dashboards. */
export const ErrorSeverity = {
  /** Informational; user can continue without action. */
  INFO: 'info',
  /** User action required but task can be retried. */
  WARNING: 'warning',
  /** Task failed; user must take corrective action. */
  ERROR: 'error',
  /** Critical failure affecting core product functionality. */
  CRITICAL: 'critical',
} as const;
export type ErrorSeverityValue = (typeof ErrorSeverity)[keyof typeof ErrorSeverity];

// ── Reports ────────────────────────────────────────────────────────────────
export const REPORTS_VIEWED = 'reports_viewed';
export const REPORT_BUILDER_OPENED = 'report_builder_opened';
export const SHARED_REPORT_VIEWED = 'shared_report_viewed';
export const REPORT_SHARED = 'report_shared';
export const REPORT_DOWNLOADED = 'report_downloaded';

// ── Billing (extended) ─────────────────────────────────────────────────────
export const ANNUAL_UPSELL_CLICKED = 'annual_upsell_clicked';
export const UPGRADE_PROMPT_CLICKED = 'upgrade_prompt_clicked';
export const TEAM_UPGRADE_TEASER_SHOWN = 'team_upgrade_teaser_shown';
export const TEAM_UPGRADE_TEASER_CLICKED = 'team_upgrade_teaser_clicked';
// @deprecated Use TRIAL_BANNER_DISMISSED — canonical for trial expiry UI dismissal.
export const TRIAL_NUDGE_DISMISSED = 'trial_nudge_dismissed';
// @deprecated Use TRIAL_BANNER_SHOWN — canonical for trial expiry UI shown.
export const TRIAL_NUDGE_SHOWN = 'trial_nudge_shown';
// @deprecated Use TRIAL_BANNER_UPGRADE_CLICKED — canonical for trial expiry upgrade CTA.
export const TRIAL_NUDGE_UPGRADE_CLICKED = 'trial_nudge_upgrade_clicked';
export const ENTERPRISE_CONTACT_SUBMITTED = 'enterprise_contact_submitted';
export const ENTERPRISE_TEAM_FALLBACK_CLICKED = 'enterprise_team_fallback_clicked';
export const CHECKOUT_SUCCESS_CTA_CLICKED = 'checkout_success_cta_clicked';

// ── Marketing (extended) ───────────────────────────────────────────────────
// Canonical marketing_ prefixed constants (use these in new code).
export const MARKETING_REGISTER_CLICK_FROM_USE_CASE_PAGE =
  'marketing_register_click_from_use_case_page';
export const MARKETING_USE_CASE_CTA_CLICKED = 'marketing_use_case_cta_clicked';
export const MARKETING_COMPARISON_HUB_CARD_CLICK = 'marketing_comparison_hub_card_clicked';
export const MARKETING_BLOG_TO_PRODUCT_CTA_CLICK = 'marketing_blog_to_product_cta_clicked';
export const MARKETING_BLOG_TO_PRICING_CLICK = 'marketing_blog_to_pricing_clicked';
// @deprecated Use MARKETING_REGISTER_CLICK_FROM_USE_CASE_PAGE — prefixed canonical for analytics filtering.
export const REGISTER_CLICK_FROM_USE_CASE_PAGE = 'register_click_from_use_case_page';
export const USE_CASE_TO_BLOG_CLICK = 'use_case_to_blog_clicked';
// @deprecated Use MARKETING_USE_CASE_CTA_CLICKED — prefixed canonical for analytics filtering.
export const USE_CASE_CTA_CLICKED = 'use_case_cta_clicked';
// @deprecated Use MARKETING_COMPARISON_HUB_CARD_CLICK — prefixed canonical for analytics filtering.
export const COMPARISON_HUB_CARD_CLICK = 'comparison_hub_card_click';
export const COMPARISON_CTA_CLICKED = 'comparison_cta_clicked';
export const PRICING_CTA_CLICKED = 'pricing_cta_clicked';
// @deprecated Use MARKETING_BLOG_TO_PRODUCT_CTA_CLICK — prefixed canonical for analytics filtering.
export const BLOG_TO_PRODUCT_CTA_CLICK = 'blog_to_product_cta_click';
export const BLOG_CATEGORY_FILTER_CLICK = 'blog_category_filter_clicked';
export const CASE_STUDY_CTA_CLICKED = 'case_study_cta_clicked';

// ── Marketing Engagement ────────────────────────────────────────────────────
/** Fired when a user reaches a scroll depth milestone on a marketing page. */
export const MARKETING_SCROLL_DEPTH_REACHED = 'marketing_scroll_depth_reached';
/** Fired when a user reaches a scroll depth milestone on a product/app page. */
export const SCROLL_DEPTH = 'scroll_depth';
/** Properties for MARKETING_SCROLL_DEPTH_REACHED events. */
export interface ScrollDepthProps {
  /** Scroll depth milestone percentage (25, 50, 75, or 100). */
  depth_percentage: 25 | 50 | 75 | 100;
  /** Slug or identifier of the marketing page (e.g. 'pricing', 'features', 'vs-semrush'). */
  page_name: string;
}

// ── Billing — Canonical Conversion Events ──────────────────────────────────
/**
 * Canonical upgrade intent event fired from all upgrade CTAs.
 * Always include source_component so PostHog can attribute conversions by surface.
 * Surface-specific events (TRIAL_BANNER_UPGRADE_CLICKED, FEATURE_GATE_UPGRADE_CLICKED,
 * QUOTA_EXHAUSTED_UPGRADE_CLICKED, LIMITS_BAR_UPGRADE_CLICKED) remain as secondary
 * events for surface-level dashboards.
 */
export const UPGRADE_CLICKED = 'upgrade_clicked';

// ── Billing UI ─────────────────────────────────────────────────────────────
export const ANNUAL_BILLING_SELECTED = 'annual_billing_selected';
export const TRIAL_BANNER_DISMISSED = 'trial_banner_dismissed';
export const TRIAL_BANNER_SHOWN = 'trial_banner_shown';
export const TRIAL_BANNER_UPGRADE_CLICKED = 'trial_banner_upgrade_clicked';
export const DUNNING_BANNER_UPDATE_CLICKED = 'dunning_banner_update_clicked';
export const DUNNING_MODAL_UPDATE_CLICKED = 'dunning_modal_update_clicked';
export const DUNNING_MODAL_DISMISSED = 'dunning_modal_dismissed';
export const SWAP_CONFIRMATION_SHOWN = 'swap_confirmation_shown';
export const SWAP_CONFIRMED = 'swap_confirmed';
export const SWAP_ABANDONED = 'swap_abandoned';
export const RETENTION_OFFER_ACCEPTED = 'retention_offer_accepted';
export const RETENTION_OFFER_SHOWN = 'retention_offer_shown';
export const CANCELLATION_CONFIRMED = 'cancellation_confirmed';

// ── Checkout ──────────────────────────────────────────────────────────────
export const CHECKOUT_LANDING = 'checkout_landing';

// ── Community ──────────────────────────────────────────────────────────────
export const FEATURES_LEARN_MORE_CLICK = 'features_learn_more_clicked';
export const COMMUNITY_LINK_CLICKED = 'community_link_clicked';
/** Fired when a user casts a vote on a public roadmap item. */
export const ROADMAP_VOTE_CAST = 'roadmap_vote_cast';

// ── Notifications ──────────────────────────────────────────────────────────
/** @server-only Notification dispatched to user channel (email, database, broadcast). Tracked via AnalyticsEventService. */
export const NOTIFICATION_DELIVERED = 'notification_delivered';
/** User opened the in-app notification dropdown or notification detail (client-side). */
export const NOTIFICATION_OPENED = 'notification_opened';
/** User clicked a CTA inside a notification (client-side). */
export const NOTIFICATION_CLICKED = 'notification_clicked';

// ── Page Engagement ──────────────────────────────────────────────────────────
/**
 * Fired on page unload (Inertia navigation or tab/window close) with scroll depth
 * and active time for the current page view. Distinguishes bounces from engaged
 * reads in PostHog. Use `usePageEngagement` hook to instrument any layout.
 */
export const PAGE_ENGAGEMENT = 'page_engagement';

// ── Feedback Loop ──────────────────────────────────────────────────────────
/** @server-only Fired when a changelog entry is published and a FeedbackShippedNotification is sent
 *  to the feedback submitter. Properties: changelog_entry_id, feedback_submission_id, user_id. */
export const FEEDBACK_LOOP_CLOSED = 'feedback_loop_closed';

// ── Engagement ─────────────────────────────────────────────────────────────
export const FEEDBACK_SUBMITTED = 'feedback_submitted';
export const QUOTA_EXHAUSTED_UPGRADE_CLICKED = 'quota_exhausted_upgrade_clicked';
/** Fired when a paid-plan user clicks the BYOK setup CTA in the quota-exhausted modal. */
export const BYOK_SETUP_PROMPTED = 'byok_setup_prompted';
export const LIMITS_BAR_UPGRADE_CLICKED = 'limits_bar_upgrade_clicked';
/**
 * Properties for LIMIT_HIT events. Disambiguates approaching, at, or over limit.
 *
 * - `percentage_used` < 100: approaching limit warning
 * - `percentage_used` === 100: exactly at limit
 * - `percentage_used` > 100: over limit (edge case — enforce at service layer to prevent)
 */
export interface LimitHitProps {
  /** The limit resource type (e.g. 'sites', 'drafts', 'ai_jobs', 'pages'). */
  limit_type: string;
  /** Current usage count at the time the event fired. */
  current_count: number;
  /** Maximum allowed count for this limit tier. */
  max_count: number;
  /** Usage expressed as a percentage (0–100+). Use to distinguish warning vs hard block. */
  percentage_used: number;
}

export const LIMIT_HIT = 'limit_hit';
/**
 * Fired when a user is near/at a resource limit — signals Product-Qualified Lead status.
 * Dispatched client-side from UpgradePrompt.tsx (consent-gated PostHog) AND server-side
 * via POST /api/lead-score/pql-signal (consent-independent lead score update).
 */
export const PQL_SIGNAL = 'pql_signal';

/**
 * Fired when a user's lead score first crosses the PQL threshold (score ≥ 76).
 * Triggers personalized upgrade pipeline: in-app banner + personalized email.
 */
export const PQL_THRESHOLD_REACHED = 'pql_threshold_reached';

/**
 * Fired when a PQL user converts to a paid plan.
 * Properties: lead_score (number), plan (string), source (string).
 */
export const PQL_CONVERTED = 'pql_converted';

// ── Admin Panel ───────────────────────────────────────────────────────────────
/** Fired when an admin views the billing/revenue dashboard. */
export const ADMIN_BILLING_DASHBOARD_VIEWED = 'admin_billing_dashboard_viewed';
/** Fired when an admin views the analysis findings list. */
export const ADMIN_FINDINGS_VIEWED = 'admin_findings_viewed';
/** Fired when an admin views the report templates list. */
export const ADMIN_REPORT_TEMPLATES_VIEWED = 'admin_report_templates_viewed';
/** Fired when an admin creates a new report template. */
export const ADMIN_REPORT_TEMPLATE_CREATED = 'admin_report_template_created';
/** Fired when an admin updates an existing report template. */
export const ADMIN_REPORT_TEMPLATE_UPDATED = 'admin_report_template_updated';
/** Fired when an admin deletes a report template. */
export const ADMIN_REPORT_TEMPLATE_DELETED = 'admin_report_template_deleted';

// ── Canonical Event Registry ────────────────────────────────────────────────
/**
 * Maps deprecated or duplicate event names to their canonical equivalents.
 * Analytics consumers should prefer canonical names in new queries.
 *
 * Canonical events per funnel stage:
 *   Wizard entered:        onboarding_wizard_viewed   (once per session, at mount)
 *   Per-step view:         onboarding_step_viewed     (multiple per session, granular)
 *   Wizard completed:      onboarding_completed       (canonical, actually emitted)
 *   Trial expiry UI:       trial_banner_{shown,dismissed,upgrade_clicked}
 *   Registration started:  REGISTRATION_STARTED       (replaces FUNNEL_REGISTRATION_STARTED)
 *   Site created:          SITE_CREATED               (replaces FUNNEL_SITE_CREATED)
 *
 * Note: FUNNEL_REGISTRATION_STARTED and FUNNEL_SITE_CREATED map to the same GA4 event
 * strings as their canonical replacements (REGISTRATION_STARTED, SITE_CREATED), so no
 * runtime remapping is needed — they are listed above for documentation only.
 */
export const LEGACY_EVENT_MAP: Readonly<Record<string, string>> = {
  // Onboarding completion: both STEP_COMPLETED and WIZARD_COMPLETED are unused;
  // canonical emitted event is onboarding_completed.
  [ONBOARDING_STEP_COMPLETED]: ONBOARDING_COMPLETED,
  [ONBOARDING_WIZARD_COMPLETED]: ONBOARDING_COMPLETED,
  // Trial expiry: NUDGE_ naming is a duplicate domain for the same UI; canonical is BANNER_.
  [TRIAL_NUDGE_SHOWN]: TRIAL_BANNER_SHOWN,
  [TRIAL_NUDGE_DISMISSED]: TRIAL_BANNER_DISMISSED,
  [TRIAL_NUDGE_UPGRADE_CLICKED]: TRIAL_BANNER_UPGRADE_CLICKED,
  // Marketing: unprefixed → marketing_ prefixed canonical names (TAXON-009).
  [REGISTER_CLICK_FROM_USE_CASE_PAGE]: MARKETING_REGISTER_CLICK_FROM_USE_CASE_PAGE,
  [USE_CASE_CTA_CLICKED]: MARKETING_USE_CASE_CTA_CLICKED,
  [COMPARISON_HUB_CARD_CLICK]: MARKETING_COMPARISON_HUB_CARD_CLICK,
  [BLOG_TO_PRODUCT_CTA_CLICK]: MARKETING_BLOG_TO_PRODUCT_CTA_CLICK,
  // _click → _clicked suffix standardization (TAXON-001): old string values for analytics consumers
  // that still emit the pre-fix event names.
  marketing_comparison_hub_card_click: MARKETING_COMPARISON_HUB_CARD_CLICK,
  marketing_blog_to_product_cta_click: MARKETING_BLOG_TO_PRODUCT_CTA_CLICK,
  use_case_to_blog_click: USE_CASE_TO_BLOG_CLICK,
  blog_category_filter_click: BLOG_CATEGORY_FILTER_CLICK,
  features_learn_more_click: FEATURES_LEARN_MORE_CLICK,
} as const;
