"use client";

import { useEffect } from "react";

import {
  consumePendingChatUnlock,
  peekPendingChatUnlock,
  type PendingChatUnlock,
  type PendingChatUnlockKind,
} from "@/lib/navigation/chat_unlock_session";
import { useAppNavigator } from "@/router/use-app-navigator";
import { useChatDispatch, useChatState } from "@/stores/chat/chat-context";
import type { ChatUnlockPaywallRequest } from "@/stores/chat/chat-state";
import { useUserState } from "@/stores/user/user-context";

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

export interface UseChatUnlockNavigationFlowInput {
  returnUrl: string;
  expectedKind?: PendingChatUnlockKind;
  expectedMessageId?: string;
  ignoredKind?: PendingChatUnlockKind;
  enabled?: boolean;
}

export interface UseChatUnlockNavigationFlowOutput {
  unlockPaywallRequest: ChatUnlockPaywallRequest | null;
  requestMessageUnlock: (
    messageId: string,
    kind: PendingChatUnlockKind,
  ) => void;
  closeInsufficientCreditsDialog: () => void;
  confirmInsufficientCreditsDialog: () => void;
}

export function useChatUnlockNavigationFlow({
  returnUrl,
  expectedKind,
  expectedMessageId,
  ignoredKind,
  enabled = true,
}: UseChatUnlockNavigationFlowInput): UseChatUnlockNavigationFlowOutput {
  const navigator = useAppNavigator();
  const userState = useUserState();
  const chatState = useChatState();
  const chatDispatch = useChatDispatch();
  const unlockPaywallRequest = getScopedUnlockPaywallRequest({
    request: chatState.unlockPaywallRequest,
    expectedKind,
    expectedMessageId,
    ignoredKind,
    enabled,
  });

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

    let cancelled = false;

    const resumePendingUnlock = async () => {
      const pending = await peekPendingChatUnlock();
      if (
        cancelled ||
        !pending ||
        pending.returnUrl !== returnUrl ||
        !matchesPendingUnlockScope({
          pending,
          expectedKind,
          expectedMessageId,
        })
      ) {
        return;
      }

      const consumed = await consumePendingChatUnlock();
      if (cancelled || !consumed) return;

      chatDispatch({
        type: "ChatUnlockMessageRequested",
        messageId: consumed.messageId,
        kind: consumed.kind,
      });
    };

    void resumePendingUnlock();
    return () => {
      cancelled = true;
    };
  }, [
    chatDispatch,
    chatState.historyLoaded,
    enabled,
    expectedKind,
    expectedMessageId,
    ignoredKind,
    navigator.isAuthenticatedUser,
    returnUrl,
  ]);

  function requestMessageUnlock(
    messageId: string,
    kind: PendingChatUnlockKind,
  ): void {
    navigator.startMessageUnlock({
      messageId,
      kind,
      returnUrl,
      onAuthenticated: () => {
        chatDispatch({
          type: "ChatUnlockMessageRequested",
          messageId,
          kind,
        });
      },
    });
  }

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

  function confirmInsufficientCreditsDialog(): void {
    if (!unlockPaywallRequest) return;

    chatDispatch({ type: "ChatUnlockPaywallNavigationConsumed" });
    navigator.openSubscriptionForPendingUnlock({
      messageId: unlockPaywallRequest.messageId,
      kind: unlockPaywallRequest.kind,
      returnUrl,
      type: getInsufficientCreditsSubscriptionType(userState.isVip),
    });
  }

  return {
    unlockPaywallRequest,
    requestMessageUnlock,
    closeInsufficientCreditsDialog,
    confirmInsufficientCreditsDialog,
  };
}

function getScopedUnlockPaywallRequest(input: {
  request: ChatUnlockPaywallRequest | null;
  expectedKind?: PendingChatUnlockKind;
  expectedMessageId?: string;
  ignoredKind?: PendingChatUnlockKind;
  enabled?: boolean;
}): ChatUnlockPaywallRequest | null {
  const {
    request,
    expectedKind,
    expectedMessageId,
    ignoredKind,
    enabled = true,
  } = input;
  if (!enabled) return null;
  if (!request) return null;
  if (ignoredKind && request.kind === ignoredKind) return null;
  if (expectedKind && request.kind !== expectedKind) return null;
  if (expectedMessageId && request.messageId !== expectedMessageId) return null;
  return request;
}

function matchesPendingUnlockScope(input: {
  pending: PendingChatUnlock;
  expectedKind?: PendingChatUnlockKind;
  expectedMessageId?: string;
}): boolean {
  const { pending, expectedKind, expectedMessageId } = input;
  if (expectedKind && pending.kind !== expectedKind) return false;
  if (expectedMessageId && pending.messageId !== expectedMessageId) {
    return false;
  }
  return true;
}
