"use client";

import { useEffect, useRef } from "react";
import { shallowEqual } from "@xstate/react";

import type { ChatLockType } from "@/data/schemas/chat";
import { behaviorAnalytics } from "@/lib/analytics";
import {
  consumePendingChatUnlock,
  peekPendingChatUnlock,
  type PendingChatPromotion,
  type PendingChatUnlock,
  type PendingChatUnlockKind,
} from "@/lib/navigation/chat_unlock_session";
import { useAppNavigator } from "@/router/use-app-navigator";
import {
  useChatDispatch,
  useChatSelector,
} from "@/stores/chat/chat-context";
import type { ChatPromotionState } from "@/stores/chat/helper/promotion";
import type { ChatUnlockPaywallRequest } from "@/stores/chat/chat-state";
import type { UiMessage } from "@/stores/chat/ui-message";
import { recordChatActionEventById } from "@/lib/chat/chat_action_events";
import { useUserSelector } from "@/stores/user/user-context";

import { getInsufficientCreditsSubscriptionType } from "../chat-screen.helpers";

export interface ChatUnlockCoordinatorScope {
  defaultReturnUrl: string;
  imageMessageId: string | null;
  imageReturnUrl: string;
  promotion: ChatPromotionState | null;
}

export interface CoordinatedMessageUnlockRequest {
  displayMessageId: string;
  messageId?: string;
  kind: PendingChatUnlockKind;
  lockType?: ChatLockType;
  clientLockId?: string;
  promotion?: PendingChatPromotion;
  returnUrl: string;
}

export interface ChatUnlockDialogModel {
  unlockPaywallRequest: ChatUnlockPaywallRequest | null;
  historyUnlock: {
    open: boolean;
    lockedCount: number;
    isLoading: boolean;
    errorMessage: string | null;
    guidance: import("@/data/schemas/chat").PaymentGuidance | null;
  };
  closeHistoryUnlock: () => void;
  confirmHistoryUnlock: () => void;
  closePaywall: () => void;
  confirmPaywall: () => void;
}

export interface UseChatUnlockCoordinatorInput
  extends ChatUnlockCoordinatorScope {
  enabled?: boolean;
}

export interface UseChatUnlockCoordinatorOutput {
  requestMessageUnlock: (input: {
    displayMessageId: string;
    remoteMessageId?: string;
    kind: PendingChatUnlockKind;
  }) => void;
  dialogs: ChatUnlockDialogModel;
}

export function useChatUnlockCoordinator({
  defaultReturnUrl,
  imageMessageId,
  imageReturnUrl,
  promotion,
  enabled = true,
}: UseChatUnlockCoordinatorInput): UseChatUnlockCoordinatorOutput {
  const navigator = useAppNavigator();
  const isVip = useUserSelector((state) => state.context.isVip);
  const trackedPaywallRef = useRef<string | null>(null);
  const chatState = useChatSelector(
    (state) => ({
      characterId: state.context.characterId,
      historyLoaded: state.context.historyLoaded,
      messages: state.context.messages,
      isUnlockingHistory: state.matches({ userSession: "unlockingHistory" }),
      lockedHistoryCount: state.context.lockedHistoryCount,
      unlockHistoryError: state.context.unlockHistoryError,
      unlockHistoryPaymentGuidance:
        state.context.unlockHistoryPaymentGuidance,
      unlockHistoryPromptVisible: state.context.unlockHistoryPromptVisible,
      unlockPaywallRequest: state.context.unlockPaywallRequest,
    }),
    shallowEqual,
  );
  const chatDispatch = useChatDispatch();
  const unlockPaywallRequest = enabled
    ? chatState.unlockPaywallRequest
    : null;

  useEffect(() => {
    const guidance = chatState.unlockHistoryPaymentGuidance;
    if (!enabled || guidance?.characterId !== chatState.characterId) return;
    void recordChatActionEventById(
      guidance.guidanceId,
      chatState.characterId,
      "viewed",
    ).catch(() => undefined);
  }, [
    chatState.characterId,
    chatState.unlockHistoryPaymentGuidance,
    enabled,
  ]);

  useEffect(() => {
    if (!unlockPaywallRequest) {
      trackedPaywallRef.current = null;
      return;
    }

    const requestKey = [
      unlockPaywallRequest.displayMessageId,
      unlockPaywallRequest.messageId ?? "",
      unlockPaywallRequest.kind,
      unlockPaywallRequest.clientLockId ?? "",
    ].join(":");
    if (trackedPaywallRef.current === requestKey) return;
    trackedPaywallRef.current = requestKey;
    behaviorAnalytics.paywallShown(
      {
        entryPoint: "chat_unlock",
        triggerReason: unlockPaywallRequest.promotion
          ? "ad_landing"
          : "insufficient_credits",
      },
      { isVip },
    );
    const guidance = unlockPaywallRequest.paymentGuidance;
    if (guidance?.characterId === chatState.characterId) {
      void recordChatActionEventById(
        guidance.guidanceId,
        chatState.characterId,
        "viewed",
      ).catch(() => undefined);
    }
  }, [chatState.characterId, isVip, unlockPaywallRequest]);

  useEffect(() => {
    if (!enabled) return;
    if (!chatState.historyLoaded || !navigator.isAuthenticatedUser) return;

    let cancelled = false;

    const resumePendingUnlock = async () => {
      const pending = await peekPendingChatUnlock(chatState.characterId);
      if (
        cancelled ||
        !pending ||
        !shouldResumePendingChatUnlock(pending, {
          defaultReturnUrl,
          imageMessageId,
          imageReturnUrl,
        })
      ) {
        return;
      }

      const consumed = await consumePendingChatUnlock(chatState.characterId);
      if (cancelled || !consumed) return;
      const displayMessageId = resolvePendingUnlockDisplayMessageId(
        consumed,
        chatState.messages,
        promotion,
      );

      chatDispatch({
        type: "ChatUnlockMessageRequested",
        displayMessageId,
        remoteMessageId: consumed.messageId,
        kind: consumed.kind,
        lockType: consumed.lockType,
        clientLockId: consumed.clientLockId,
      });
    };

    void resumePendingUnlock();
    return () => {
      cancelled = true;
    };
  }, [
    chatDispatch,
    chatState.characterId,
    chatState.historyLoaded,
    defaultReturnUrl,
    enabled,
    imageMessageId,
    imageReturnUrl,
    navigator.isAuthenticatedUser,
    promotion,
    chatState.messages,
  ]);

  function requestMessageUnlock(input: {
    displayMessageId: string;
    remoteMessageId?: string;
    kind: PendingChatUnlockKind;
  }): void {
    const request = resolveMessageUnlockRequest(
      input,
      {
        defaultReturnUrl,
        imageMessageId,
        imageReturnUrl,
        promotion,
      },
    );

    navigator.startMessageUnlock({
      ...request,
      onAuthenticated: () => {
        chatDispatch({
          type: "ChatUnlockMessageRequested",
          displayMessageId: request.displayMessageId,
          remoteMessageId: request.messageId,
          kind: request.kind,
          lockType: request.lockType,
          clientLockId: request.clientLockId,
        });
      },
    });
  }

  function closeHistoryUnlock(): void {
    chatDispatch({ type: "ChatUnlockHistoryDismissed" });
  }

  function confirmHistoryUnlock(): void {
    const guidance =
      chatState.unlockHistoryPaymentGuidance?.characterId ===
      chatState.characterId
        ? chatState.unlockHistoryPaymentGuidance
        : null;
    if (guidance) {
      if (guidance.mode !== "guide") return;
      void recordChatActionEventById(
        guidance.guidanceId,
        chatState.characterId,
        "opened",
      ).catch(() => undefined);
      navigator.openSubscription({
        type:
          isVip || !guidance.purchaseOptions.includes("vip")
            ? "topup"
            : "vip",
        returnTo: "chat",
        chatActionId: guidance.guidanceId,
        analytics: {
          entryPoint: "chat_unlock",
          triggerReason: "insufficient_credits",
        },
      });
      return;
    }
    chatDispatch({ type: "ChatUnlockHistoryConfirmed" });
  }

  function closePaywall(): void {
    chatDispatch({ type: "ChatUnlockPaywallNavigationConsumed" });
  }

  function confirmPaywall(): void {
    if (!unlockPaywallRequest) return;
    const guidance =
      unlockPaywallRequest.paymentGuidance?.characterId ===
      chatState.characterId
        ? unlockPaywallRequest.paymentGuidance
        : null;
    if (guidance && guidance.mode !== "guide") return;

    const returnUrl = resolveChatUnlockReturnUrl(
      unlockPaywallRequest,
      {
        defaultReturnUrl,
        imageMessageId,
        imageReturnUrl,
      },
    );
    chatDispatch({ type: "ChatUnlockPaywallNavigationConsumed" });
    if (guidance) {
      void recordChatActionEventById(
        guidance.guidanceId,
        chatState.characterId,
        "opened",
      ).catch(() => undefined);
    }
    navigator.openSubscriptionForPendingUnlock({
      displayMessageId: unlockPaywallRequest.displayMessageId,
      messageId: unlockPaywallRequest.messageId,
      kind: unlockPaywallRequest.kind,
      lockType: unlockPaywallRequest.lockType,
      clientLockId: unlockPaywallRequest.clientLockId,
      promotion: unlockPaywallRequest.promotion,
      returnUrl,
      type:
        isVip || (guidance && !guidance.purchaseOptions.includes("vip"))
          ? "topup"
          : getInsufficientCreditsSubscriptionType(isVip),
      analytics: {
        entryPoint: "chat_unlock",
        triggerReason: unlockPaywallRequest.promotion
          ? "ad_landing"
          : "insufficient_credits",
      },
      ...(guidance ? { chatActionId: guidance.guidanceId } : {}),
    });
  }

  return {
    requestMessageUnlock,
    dialogs: {
      unlockPaywallRequest,
      historyUnlock: {
        open: chatState.unlockHistoryPromptVisible,
        lockedCount: chatState.lockedHistoryCount,
        isLoading: chatState.isUnlockingHistory,
        errorMessage: chatState.unlockHistoryError,
        guidance: chatState.unlockHistoryPaymentGuidance,
      },
      closeHistoryUnlock,
      confirmHistoryUnlock,
      closePaywall,
      confirmPaywall,
    },
  };
}

export function resolveMessageUnlockRequest(
  input: {
    displayMessageId: string;
    remoteMessageId?: string;
    kind: PendingChatUnlockKind;
  },
  scope: ChatUnlockCoordinatorScope,
): CoordinatedMessageUnlockRequest {
  const matchedPromotion =
    scope.promotion?.message.displayId === input.displayMessageId
      ? scope.promotion
      : null;
  const remoteMessageId =
    input.remoteMessageId ?? matchedPromotion?.message.remoteId;
  const target = {
    displayMessageId: input.displayMessageId,
    ...(remoteMessageId ? { messageId: remoteMessageId } : {}),
    kind: input.kind,
    ...(matchedPromotion
      ? {
          lockType: matchedPromotion.session.lockType,
          clientLockId: matchedPromotion.session.clientLockId,
          promotion: matchedPromotion.session,
        }
      : {}),
  };

  return {
    ...target,
    returnUrl: resolveChatUnlockReturnUrl(target, scope),
  };
}

export function shouldResumePendingChatUnlock(
  pending: PendingChatUnlock,
  scope: Omit<ChatUnlockCoordinatorScope, "promotion">,
): boolean {
  if (pending.returnUrl === scope.defaultReturnUrl) return true;
  if (pending.returnUrl !== scope.imageReturnUrl) return false;
  return isCurrentImageUnlock(pending, scope.imageMessageId);
}

export function resolvePendingUnlockDisplayMessageId(
  pending: PendingChatUnlock,
  messages: readonly UiMessage[],
  promotion: ChatPromotionState | null,
): string {
  if (
    promotion &&
    (promotion.message.displayId === pending.displayMessageId ||
      (pending.messageId &&
        promotion.message.remoteId === pending.messageId))
  ) {
    return promotion.message.displayId;
  }

  const exactMessage = messages.find(
    (message) => message.displayId === pending.displayMessageId,
  );
  if (exactMessage) return exactMessage.displayId;
  if (!pending.messageId) return pending.displayMessageId;

  const remoteMessage =
    messages.find(
      (message) =>
        message.isFromAI &&
        message.locked === true &&
        message.remoteId === pending.messageId,
    ) ??
    messages.find(
      (message) =>
        message.isFromAI && message.remoteId === pending.messageId,
    );
  return remoteMessage?.displayId ?? pending.displayMessageId;
}

export function resolveChatUnlockReturnUrl(
  target: Pick<
    CoordinatedMessageUnlockRequest,
    "displayMessageId" | "messageId" | "kind" | "promotion"
  >,
  scope: Pick<
    ChatUnlockCoordinatorScope,
    "defaultReturnUrl" | "imageMessageId" | "imageReturnUrl"
  >,
): string {
  return isCurrentImageUnlock(target, scope.imageMessageId)
    ? scope.imageReturnUrl
    : scope.defaultReturnUrl;
}

function isCurrentImageUnlock(
  target: Pick<
    CoordinatedMessageUnlockRequest,
    "displayMessageId" | "messageId" | "kind" | "promotion"
  >,
  imageMessageId: string | null,
): boolean {
  if (target.promotion || target.kind !== "image" || !imageMessageId) {
    return false;
  }
  return (
    target.displayMessageId === imageMessageId ||
    target.messageId === imageMessageId
  );
}
