/**
 * URL pattern detection and unfurling for smart link previews.
 * Supports internal URLs (issues, PRs, commits, repos) and external URLs.
 */


export type LinkType =
  | 'issue'
  | 'pull_request'
  | 'commit'
  | 'repository'
  | 'room'
  | 'project'
  | 'external';

export interface UnfurlResult {
  type: LinkType;
  url: string;
  /** Parsed entity ID fields */
  ids: {
    project?: string;
    namespace?: string;
    repo?: string;
    issueNumber?: number;
    prNumber?: number;
    commitOid?: string;
    roomId?: string;
  };
  /** Display title (populated after fetch) */
  title?: string;
  /** Extra metadata (populated after fetch) */
  meta?: Record<string, unknown>;
  /** Whether the URL is external */
  isExternal?: boolean;
  /** Domain for external URLs */
  domain?: string;
}

/** Internal URL patterns */
const INTERNAL_PATTERNS: Array<{
  type: LinkType;
  regex: RegExp;
  extract: (match: RegExpMatchArray) => UnfurlResult['ids'];
}> = [
  {
    type: 'issue',
    regex: /^\/project\/([^/]+)\/issues\/(\d+)/,
    extract: (m) => ({ project: m[1], issueNumber: parseInt(m[2], 10) }),
  },
  {
    type: 'pull_request',
    regex: /^\/repository\/([^/]+)\/([^/]+)\/pulls?\/(\d+)/,
    extract: (m) => ({ namespace: m[1], repo: m[2], prNumber: parseInt(m[3], 10) }),
  },
  {
    type: 'commit',
    regex: /^\/repository\/([^/]+)\/([^/]+)\/commit\/([a-f0-9]+)/,
    extract: (m) => ({ namespace: m[1], repo: m[2], commitOid: m[3] }),
  },
  {
    type: 'repository',
    regex: /^\/repository\/([^/]+)\/([^/]+)/,
    extract: (m) => ({ namespace: m[1], repo: m[2] }),
  },
  {
    type: 'project',
    regex: /^\/project\/([^/]+)/,
    extract: (m) => ({ project: m[1] }),
  },
  {
    type: 'room',
    regex: /^\/project\/([^/]+)\/room(?:\/([^/?#]+))?/,
    extract: (m) => ({ project: m[1], roomId: m[2] }),
  },
];

/** Detect the type and IDs of a URL */
export function detectLinkType(url: string): UnfurlResult | null {
  // Remove trailing slashes and hash
  const normalized = url.split('?')[0].split('#')[0].replace(/\/+$/, '');

  // Check internal patterns
  for (const pattern of INTERNAL_PATTERNS) {
    const match = normalized.match(pattern.regex);
    if (match) {
      return {
        type: pattern.type,
        url: `/${normalized.replace(/^\//, '')}`,
        ids: pattern.extract(match),
      };
    }
  }

  // External URL
  try {
    const parsed = new URL(url);
    const isExternal = !parsed.hostname.includes(window.location.hostname);
    return {
      type: 'external',
      url,
      ids: {},
      isExternal,
      domain: parsed.hostname,
    };
  } catch {
    return null;
  }
}

/** Extract all URLs from a text string */
export function extractUrls(text: string): Array<{ url: string; index: number }> {
  // Match URLs (including internal paths starting with /)
  const urlPattern = /(?:https?:\/\/[^\s<>"]+|^\/[^\s<>"]+|\/[^\s<>"]+)/gm;
  const results: Array<{ url: string; index: number }> = [];
  let match;

  while ((match = urlPattern.exec(text)) !== null) {
    const url = match[0];
    // Filter out very short or malformed URLs
    if (url.length > 3) {
      results.push({ url, index: match.index });
    }
  }

  return results;
}

/** Simple cache for unfurl results */
const unfurlCache = new Map<string, UnfurlResult & { expiresAt: number }>();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

export function getCachedUnfurl(url: string): (UnfurlResult & { expiresAt: number }) | undefined {
  const cached = unfurlCache.get(url);
  if (cached && cached.expiresAt > Date.now()) {
    return cached;
  }
  return undefined;
}

export function setCachedUnfurl(url: string, result: UnfurlResult): void {
  unfurlCache.set(url, { ...result, expiresAt: Date.now() + CACHE_TTL });
}
