"use client";

import type { PayChannel, PaymentPlan } from "@/data/schemas/payment";

import type {
  PaymentAnalyticsContext,
  PaymentAnalyticsEntryPoint,
  PaymentAnalyticsTriggerReason,
} from "./payment_analytics_context";

export interface BehaviorAnalyticsPlan {
  planId: string;
  planName: string;
  orderType: string;
  amountCents: number;
  currency: string;
}

export interface CozsweetBehaviorAnalyticsSdk {
  elementClick(
    key: string,
    text: string,
    metadata?: Record<string, unknown>,
  ): void;
  paywallShown(
    triggerReason: PaymentAnalyticsTriggerReason,
    metadata?: Record<string, unknown>,
  ): void;
  rechargeModalOpen(
    entryPoint: PaymentAnalyticsEntryPoint,
    triggerReason: PaymentAnalyticsTriggerReason,
    metadata?: Record<string, unknown>,
  ): void;
  planImpression(
    plan: BehaviorAnalyticsPlan,
    position: number,
    metadata?: Record<string, unknown>,
  ): void;
  planClick(
    plan: BehaviorAnalyticsPlan,
    metadata?: Record<string, unknown>,
  ): void;
  createOrderStart(
    plan: BehaviorAnalyticsPlan,
    payChannel: PayChannel,
    metadata?: Record<string, unknown>,
  ): void;
  createOrderSuccess(
    plan: BehaviorAnalyticsPlan,
    orderId: string,
    payChannel: PayChannel,
    metadata?: Record<string, unknown>,
  ): void;
  createOrderFailed(
    plan: BehaviorAnalyticsPlan,
    reason: string,
    payChannel: PayChannel,
    metadata?: Record<string, unknown>,
  ): void;
  checkoutOpened(
    orderId: string,
    plan: BehaviorAnalyticsPlan,
    payChannel: PayChannel,
    checkoutUrl: string,
    metadata?: Record<string, unknown>,
  ): void;
  checkoutFailed(
    orderId: string,
    plan: BehaviorAnalyticsPlan,
    reason: string,
    payChannel: PayChannel,
    metadata?: Record<string, unknown>,
  ): void;
  statusPollStart(
    orderId: string,
    plan?: BehaviorAnalyticsPlan,
    metadata?: Record<string, unknown>,
  ): void;
  statusPollUpdate(
    orderId: string,
    status: string,
    plan?: BehaviorAnalyticsPlan,
    metadata?: Record<string, unknown>,
  ): void;
  statusPollTimeout(
    orderId: string,
    plan?: BehaviorAnalyticsPlan,
    metadata?: Record<string, unknown>,
  ): void;
}

declare global {
  interface Window {
    COZSWEET_ANALYTICS_ENDPOINT?: string;
    CozsweetPaymentAnalytics?: CozsweetBehaviorAnalyticsSdk;
  }
}

export function toBehaviorAnalyticsPlan(
  plan: PaymentPlan,
): BehaviorAnalyticsPlan {
  return {
    planId: plan.planId,
    planName: plan.planName,
    orderType: plan.orderType,
    amountCents: plan.amountCents,
    currency: plan.currency,
  };
}

export function sanitizeAnalyticsCheckoutUrl(value: string): string {
  if (value === "stripe_embedded") return value;
  try {
    const url = new URL(value);
    if (url.protocol !== "https:" && url.protocol !== "http:") {
      return "external_checkout";
    }
    return `${url.origin}${url.pathname}`;
  } catch {
    return "external_checkout";
  }
}

function invokeAnalytics(
  callback: (analytics: CozsweetBehaviorAnalyticsSdk) => void,
): void {
  if (typeof window === "undefined") return;
  const analytics = window.CozsweetPaymentAnalytics;
  if (!analytics) return;
  try {
    callback(analytics);
  } catch {
    // Analytics must never interrupt user-facing flows.
  }
}

export const behaviorAnalytics = {
  elementClick(
    key: string,
    label: string,
    metadata?: Record<string, unknown>,
  ): void {
    invokeAnalytics((analytics) =>
      analytics.elementClick(key, label, metadata),
    );
  },
  paywallShown(
    context: PaymentAnalyticsContext,
    metadata?: { isVip?: boolean },
  ): void {
    invokeAnalytics((analytics) =>
      analytics.paywallShown(context.triggerReason, {
        entryPoint: context.entryPoint,
        ...metadata,
      }),
    );
  },
  rechargeModalOpen(context: PaymentAnalyticsContext): void {
    invokeAnalytics((analytics) =>
      analytics.rechargeModalOpen(
        context.entryPoint,
        context.triggerReason,
      ),
    );
  },
  planImpression(
    plan: PaymentPlan,
    position: number,
    context: PaymentAnalyticsContext,
  ): void {
    invokeAnalytics((analytics) =>
      analytics.planImpression(toBehaviorAnalyticsPlan(plan), position, {
        ...context,
      }),
    );
  },
  planClick(plan: PaymentPlan, context: PaymentAnalyticsContext): void {
    invokeAnalytics((analytics) =>
      analytics.planClick(toBehaviorAnalyticsPlan(plan), { ...context }),
    );
  },
  createOrderStart(plan: PaymentPlan, payChannel: PayChannel): void {
    invokeAnalytics((analytics) =>
      analytics.createOrderStart(toBehaviorAnalyticsPlan(plan), payChannel),
    );
  },
  createOrderSuccess(
    plan: PaymentPlan,
    orderId: string,
    payChannel: PayChannel,
  ): void {
    invokeAnalytics((analytics) =>
      analytics.createOrderSuccess(
        toBehaviorAnalyticsPlan(plan),
        orderId,
        payChannel,
      ),
    );
  },
  createOrderFailed(plan: PaymentPlan, payChannel: PayChannel): void {
    invokeAnalytics((analytics) =>
      analytics.createOrderFailed(
        toBehaviorAnalyticsPlan(plan),
        "create_order_error",
        payChannel,
      ),
    );
  },
  checkoutOpened(input: {
    orderId: string;
    plan: PaymentPlan;
    payChannel: PayChannel;
    checkoutUrl: string;
  }): void {
    invokeAnalytics((analytics) =>
      analytics.checkoutOpened(
        input.orderId,
        toBehaviorAnalyticsPlan(input.plan),
        input.payChannel,
        sanitizeAnalyticsCheckoutUrl(input.checkoutUrl),
      ),
    );
  },
  checkoutFailed(input: {
    orderId: string;
    plan: PaymentPlan;
    payChannel: PayChannel;
    reason: "missing_checkout_url" | "payment_redirect_failed";
  }): void {
    invokeAnalytics((analytics) =>
      analytics.checkoutFailed(
        input.orderId,
        toBehaviorAnalyticsPlan(input.plan),
        input.reason,
        input.payChannel,
      ),
    );
  },
  statusPollStart(orderId: string, plan?: PaymentPlan): void {
    invokeAnalytics((analytics) =>
      analytics.statusPollStart(
        orderId,
        plan ? toBehaviorAnalyticsPlan(plan) : undefined,
      ),
    );
  },
  statusPollUpdate(
    orderId: string,
    status: string,
    plan?: PaymentPlan,
  ): void {
    invokeAnalytics((analytics) =>
      analytics.statusPollUpdate(
        orderId,
        status,
        plan ? toBehaviorAnalyticsPlan(plan) : undefined,
      ),
    );
  },
  statusPollTimeout(orderId: string, plan?: PaymentPlan): void {
    invokeAnalytics((analytics) =>
      analytics.statusPollTimeout(
        orderId,
        plan ? toBehaviorAnalyticsPlan(plan) : undefined,
      ),
    );
  },
};
