import { normalizeChatResourceUrl } from './chatResourceUrl';
import { extractAttachmentPreviewUrls, extractChatMessageParts } from './messageParts';
import { extractHiddenPreviewUrls } from './previewMarkers';
import { classifyPreviewKind, type PreviewKind } from './previewKind';
import type { ChatMessage } from './types';

export type PreviewItem = {
  id: string;
  label: string;
  url: string;
  kind: PreviewKind;
  source: 'message' | 'context';
};

const CHAT_RESOURCE_INTERNAL_SEGMENTS = new Set(['resource', 'uploads', 'source', 'src']);
const CHAT_RESOURCE_HIDDEN_FILE_NAMES = new Set(['.env']);
const CHAT_API_RESOURCE_MARKER = '/api/chat/resources/';
const RESOURCE_STRIP_ALLOWED_KINDS = new Set<PreviewKind>([
  'image',
  'video',
  'markdown',
  'code',
  'diff',
  'document',
  'pdf',
  'file',
]);

function normalizePreviewUrl(value: string) {
  return normalizeChatResourceUrl(value);
}

function parsePreviewUrl(url: string) {
  try {
    return new URL(url, typeof window !== 'undefined' ? window.location.origin : 'https://local.invalid');
  } catch {
    return null;
  }
}

function extractInternalChatResourcePath(pathname: string) {
  const normalizedPathname = String(pathname ?? '').trim();

  if (!normalizedPathname) {
    return '';
  }

  if (normalizedPathname.includes('/.codex_chat/')) {
    const markerIndex = normalizedPathname.lastIndexOf('/.codex_chat/');
    return normalizedPathname.slice(markerIndex + 1);
  }

  const apiMarkerIndex = normalizedPathname.lastIndexOf(CHAT_API_RESOURCE_MARKER);
  if (apiMarkerIndex >= 0) {
    return normalizedPathname.slice(apiMarkerIndex + CHAT_API_RESOURCE_MARKER.length).replace(/^\/+/, '');
  }

  return '';
}

function hasVisibleFileExtension(fileName: string) {
  return /\.[a-z0-9]{1,16}$/i.test(fileName);
}

function hasSupportedPreviewFileExtension(fileName: string) {
  return /\.(png|jpe?g|gif|webp|svg|bmp|ico|mp4|webm|mov|m4v|ogg|md|markdown|diff|patch|ts|tsx|js|jsx|json|css|scss|html|xml|java|kt|sql|sh|py|go|rs|c|cpp|h|hpp|yml|yaml|txt|log|csv|pdf)$/i.test(
    fileName,
  );
}

function isMarkdownResourceFile(fileName: string) {
  return /\.(md|markdown)$/i.test(fileName);
}

function shouldHideInternalChatResource(url: string) {
  const parsed = parsePreviewUrl(url);
  const pathname = parsed?.pathname ?? '';
  const internalResourcePath = extractInternalChatResourcePath(pathname);
  const normalizedInternalResourcePath = internalResourcePath.toLowerCase();

  if (!normalizedInternalResourcePath.startsWith('.codex_chat/')) {
    return false;
  }

  const segments = internalResourcePath.split('/').filter(Boolean);
  const lastSegment = segments.at(-1)?.trim() ?? '';
  const normalizedLastSegment = lastSegment.toLowerCase();
  const resourceSegmentIndex = segments.findIndex((segment) => segment === 'resource');
  const nextSegment = resourceSegmentIndex >= 0 ? segments[resourceSegmentIndex + 1]?.toLowerCase() ?? '' : '';

  if (!lastSegment || pathname.endsWith('/')) {
    return true;
  }

  if (CHAT_RESOURCE_INTERNAL_SEGMENTS.has(normalizedLastSegment)) {
    return true;
  }

  if (!hasVisibleFileExtension(lastSegment)) {
    return true;
  }

  if (CHAT_RESOURCE_INTERNAL_SEGMENTS.has(nextSegment) && !hasVisibleFileExtension(lastSegment)) {
    return true;
  }

  if (normalizedLastSegment.startsWith('.')) {
    return true;
  }

  if (CHAT_RESOURCE_HIDDEN_FILE_NAMES.has(normalizedLastSegment)) {
    return true;
  }

  if (resourceSegmentIndex >= 0 && nextSegment === 'src' && !isMarkdownResourceFile(lastSegment)) {
    return true;
  }

  if (!hasSupportedPreviewFileExtension(lastSegment)) {
    return true;
  }

  return false;
}

export function buildPreviewLabel(url: string, source: PreviewItem['source']) {
  try {
    const parsed = new URL(url);
    const lastSegment = parsed.pathname.split('/').filter(Boolean).at(-1);

    if (lastSegment) {
      return source === 'context' ? `현재 화면 · ${lastSegment}` : lastSegment;
    }

    return source === 'context' ? '현재 화면 미리보기' : parsed.hostname;
  } catch {
    return source === 'context' ? '현재 화면 미리보기' : url;
  }
}

export function isHtmlPreviewItem(item: PreviewItem | null | undefined) {
  if (!item || item.kind !== 'code') {
    return false;
  }

  try {
    const parsed = new URL(item.url, typeof window !== 'undefined' ? window.location.origin : 'https://local.invalid');
    const pathname = parsed.pathname.toLowerCase();
    return pathname.endsWith('.html') || pathname.endsWith('.htm');
  } catch {
    const pathname = item.url.toLowerCase().split('?')[0] ?? '';
    return pathname.endsWith('.html') || pathname.endsWith('.htm');
  }
}

export function extractPreviewItems(messages: ChatMessage[]) {
  const seen = new Set<string>();
  const items: PreviewItem[] = [];
  const orderedMessages = [...messages].reverse();

  orderedMessages.forEach((message) => {
    const attachmentExtraction = extractAttachmentPreviewUrls(message.text);
    const extractedMessageParts = extractChatMessageParts(attachmentExtraction.strippedText);
    const structuredLinkUrls = [
      ...(Array.isArray(message.parts) ? message.parts : []),
      ...extractedMessageParts.parts,
    ]
      .filter(
        (part): part is Extract<(typeof extractedMessageParts.parts)[number], { type: 'link_card' }> =>
          part.type === 'link_card' && Boolean(part.url),
      )
      .map((part) => part.url);
    const matches = [
      ...extractHiddenPreviewUrls(message.text),
      ...attachmentExtraction.urls,
      ...structuredLinkUrls,
    ];

    matches.forEach((matchedUrl) => {
      const normalizedUrl = normalizePreviewUrl(matchedUrl);
      const kind = classifyPreviewKind(normalizedUrl);

      if (shouldHideInternalChatResource(normalizedUrl)) {
        return;
      }

      if (!RESOURCE_STRIP_ALLOWED_KINDS.has(kind)) {
        return;
      }

      if (seen.has(normalizedUrl)) {
        return;
      }

      seen.add(normalizedUrl);
      items.push({
        id: `${message.id}-${normalizedUrl}`,
        label: buildPreviewLabel(normalizedUrl, 'message'),
        url: normalizedUrl,
        kind,
        source: 'message',
      });
    });
  });

  return items.slice(0, 12);
}
