import { useMemo, useCallback } from 'react';

import type { PageProps, UiAccessibleConfig } from '@redocly/config';
import type { PageAction, MCPClientType, McpConnectionParams } from '../types';

import { CopyIcon } from '@redocly/theme/icons/CopyIcon/CopyIcon';
import { ChatGptIcon } from '@redocly/theme/icons/ChatGptIcon/ChatGptIcon';
import { ClaudeIcon } from '@redocly/theme/icons/ClaudeIcon/ClaudeIcon';
import { MarkdownFullIcon } from '@redocly/theme/icons/MarkdownFullIcon/MarkdownFullIcon';
import { VSCodeIcon } from '@redocly/theme/icons/VSCodeIcon/VSCodeIcon';
import { CursorIcon } from '@redocly/theme/icons/CursorIcon/CursorIcon';

import { useThemeHooks } from './use-theme-hooks';
import { useThemeConfig } from './use-theme-config';
import { useMCPConfig } from './use-mcp-config';
import { ClipboardService } from '../utils/clipboard-service';
import { IS_BROWSER } from '../utils/dom';
import { generateMCPDeepLink } from '../utils/mcp';
import {
  addTrailingSlash,
  combineUrls,
  removeTrailingSlash,
  withoutPathPrefix,
} from '../utils/urls';

function createPageActionResource(pageSlug: string, pageUrl: string) {
  return {
    id: pageSlug,
    object: 'page' as const,
    uri: pageUrl,
  };
}

const DEFAULT_ENABLED_ACTIONS = [
  'copy',
  'view',
  'chatgpt',
  'claude',
  'docs-mcp-cursor',
  'docs-mcp-vscode',
] as const;

export type PageActionType =
  | 'copy'
  | 'view'
  | 'chatgpt'
  | 'claude'
  | 'docs-mcp-cursor'
  | 'docs-mcp-vscode'
  | 'mcp-cursor'
  | 'mcp-vscode';

export function usePageActions(
  pageSlug: string,
  mcpUrl?: string,
  actions?: PageActionType[],
): PageAction[] {
  const { useTranslate, usePageData, usePageProps, usePageSharedData, useTelemetry } =
    useThemeHooks();
  const { translate } = useTranslate();
  const themeConfig = useThemeConfig();
  const pageProps = usePageProps();
  const telemetry = useTelemetry();
  const openApiSharedData = usePageSharedData<
    { options: { excludeFromSearch: boolean } } | undefined
  >('openAPIDocsStore');
  const mcpConfig = useMCPConfig();

  const shouldHideAllActions = shouldHidePageActions(
    pageProps,
    themeConfig,
    openApiSharedData?.options?.excludeFromSearch,
  );
  const { isPublic } = usePageData() || {};

  const createMCPHandler = useCallback(
    (clientType: MCPClientType, requiresMcpUrl: boolean = false) =>
      () => {
        if (requiresMcpUrl && !mcpUrl) return null;
        if (!requiresMcpUrl && (mcpUrl || mcpConfig.isMcpDisabled)) return null;

        const config = requiresMcpUrl
          ? { serverName: mcpConfig.serverName, url: mcpUrl || '' }
          : { serverName: mcpConfig.serverName, url: mcpConfig.serverUrl || '' };

        const isDocsMcp = !requiresMcpUrl;

        const origin = IS_BROWSER ? window.location.origin : '';
        const pageUrl = `${origin}${pageSlug}`;

        return createMCPAction({
          clientType,
          mcpConfig: config,
          translate,
          onClickCallback: isDocsMcp
            ? () =>
                telemetry.sendPageActionsButtonClickedMessage([
                  {
                    ...createPageActionResource(pageSlug, pageUrl),
                    action_type: `docs-mcp-${clientType}` as const,
                  },
                ])
            : undefined,
        });
      },
    [mcpUrl, mcpConfig, translate, telemetry, pageSlug],
  );

  const result: PageAction[] = useMemo(() => {
    if (shouldHideAllActions) {
      return [];
    }

    const origin = IS_BROWSER
      ? window.location.origin
      : ((globalThis as { SSR_HOSTNAME?: string })['SSR_HOSTNAME'] ?? '');
    const pathname = addTrailingSlash(pageSlug);
    const pageUrl = combineUrls(origin, pathname);
    const isRoot = withoutPathPrefix(pathname) === '/';
    const mdPageUrl = isRoot
      ? combineUrls(origin, pathname, 'index.html.md')
      : combineUrls(origin, removeTrailingSlash(pathname) + '.md');

    const actionHandlers: Record<PageActionType, () => PageAction | null> = {
      'docs-mcp-cursor': createMCPHandler('cursor', false),
      'docs-mcp-vscode': createMCPHandler('vscode', false),
      'mcp-cursor': createMCPHandler('cursor', true),
      'mcp-vscode': createMCPHandler('vscode', true),

      copy: () => ({
        buttonText: translate('page.actions.copyButtonText', 'Copy'),
        title: translate('page.actions.copyTitle', 'Copy for LLM'),
        description: translate('page.actions.copyDescription', 'Copy page as Markdown for LLMs'),
        iconComponent: CopyIcon,
        onClick: async () => {
          try {
            const result = await fetch(mdPageUrl);
            if (result.status !== 200) {
              return;
            }
            const text = await result.text();
            ClipboardService.copyCustom(text);
            telemetry.sendPageActionsButtonClickedMessage([
              {
                ...createPageActionResource(pageSlug, pageUrl),
                action_type: 'copy',
              },
            ]);
          } catch (error) {
            console.error(error);
          }
        },
      }),

      view: () => ({
        buttonText: translate('page.actions.viewAsMdButtonText', 'View as Markdown'),
        title: translate('page.actions.viewAsMdTitle', 'View as Markdown'),
        description: translate('page.actions.viewAsMdDescription', 'Open this page as Markdown'),
        iconComponent: MarkdownFullIcon,
        link: mdPageUrl,
        onClick: () => {
          telemetry.sendPageActionsButtonClickedMessage([
            {
              ...createPageActionResource(pageSlug, pageUrl),
              action_type: 'view',
            },
          ]);
        },
      }),

      chatgpt: () => {
        if (!isPublic) {
          return null;
        }
        const link = getExternalAiPromptLink('https://chat.openai.com', mdPageUrl);
        return {
          buttonText: translate('page.actions.chatGptButtonText', 'Open in ChatGPT'),
          title: translate('page.actions.chatGptTitle', 'Open in ChatGPT'),
          description: translate('page.actions.chatGptDescription', 'Get insights from ChatGPT'),
          iconComponent: ChatGptIcon,
          link,
          onClick: () => {
            telemetry.sendPageActionsButtonClickedMessage([
              {
                ...createPageActionResource(pageSlug, pageUrl),
                action_type: 'chatgpt',
              },
            ]);
            window.location.href = link;
          },
        };
      },

      claude: () => {
        if (!isPublic) {
          return null;
        }
        const link = getExternalAiPromptLink('https://claude.ai/new', mdPageUrl);
        return {
          buttonText: translate('page.actions.claudeButtonText', 'Open in Claude'),
          title: translate('page.actions.claudeTitle', 'Open in Claude'),
          description: translate('page.actions.claudeDescription', 'Get insights from Claude'),
          iconComponent: ClaudeIcon,
          link,
          onClick: () => {
            telemetry.sendPageActionsButtonClickedMessage([
              {
                ...createPageActionResource(pageSlug, pageUrl),
                action_type: 'claude',
              },
            ]);
            window.location.href = link;
          },
        };
      },
    };

    return (themeConfig.navigation?.actions?.items || actions || DEFAULT_ENABLED_ACTIONS)
      .map((action) => actionHandlers[action]?.())
      .filter((action): action is PageAction => action !== null);
  }, [
    shouldHideAllActions,
    pageSlug,
    themeConfig.navigation?.actions?.items,
    actions,
    translate,
    isPublic,
    createMCPHandler,
    telemetry,
  ]);

  return result;
}

function getExternalAiPromptLink(baseUrl: string, mdPageUrl: string): string {
  const externalAiPrompt = `Read ${mdPageUrl} and answer questions based on the content.`;
  const url = new URL(baseUrl);
  url.searchParams.set('q', externalAiPrompt);
  return url.toString();
}

type CreateMCPActionParams = {
  clientType: MCPClientType;
  mcpConfig: McpConnectionParams;
  translate: (key: string, defaultValue: string) => string;
  onClickCallback?: () => void;
};

function createMCPAction({
  clientType,
  mcpConfig,
  translate,
  onClickCallback,
}: CreateMCPActionParams): PageAction {
  const url = generateMCPDeepLink(clientType, mcpConfig);
  const sharedProps = {
    onClick: () => {
      onClickCallback?.();
      window.open(url, '_blank');
    },
  };

  if (clientType === 'cursor') {
    return {
      ...sharedProps,
      buttonText: translate('page.actions.connectMcp.cursor', 'Connect to Cursor'),
      title: translate('page.actions.connectMcp.cursor', 'Connect to Cursor'),
      description: translate(
        'page.actions.connectMcp.cursorDescription',
        'Install MCP server on Cursor',
      ),
      iconComponent: CursorIcon,
    };
  }

  return {
    ...sharedProps,
    buttonText: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'),
    title: translate('page.actions.connectMcp.vscode', 'Connect to VS Code'),
    description: translate(
      'page.actions.connectMcp.vscodeDescription',
      'Install MCP server on VS Code',
    ),
    iconComponent: VSCodeIcon,
  };
}

function shouldHidePageActions(
  pageProps: PageProps,
  themeConfig: UiAccessibleConfig,
  openapiExcludeFromSearch?: boolean,
): boolean {
  // Can't use any actions if search is globally disabled (markdown files are not generated)
  if (themeConfig.search?.hide) {
    return true;
  }

  // Can't use any actions if no markdown files are generated for LLMs
  if (pageProps?.seo?.llmstxt?.hide) {
    return true;
  }

  // Page actions are explicitly disabled in config
  if (themeConfig.navigation?.actions?.hide) {
    return true;
  }

  // Page is excluded from search
  const isOpenApiPage =
    pageProps?.metadata?.type === 'openapi' || pageProps?.metadata?.subType === 'openapi-operation';
  const isPageExcludedFromSearch =
    pageProps?.frontmatter?.excludeFromSearch || (isOpenApiPage && openapiExcludeFromSearch);

  if (isPageExcludedFromSearch) {
    return true;
  }

  return false;
}
