/* eslint-disable @typescript-eslint/member-ordering */
import { CommonModule } from '@angular/common';
import {
  Component,
  computed,
  inject,
  input
} from '@angular/core';
import { MermaidComponent, RemarkModule } from 'ngx-remark';
import remarkBreaks from 'remark-breaks';
import remarkGfm from 'remark-gfm';
import remarkParse from 'remark-parse';
import { unified } from 'unified';
import { remarkStripDangerousContent } from '../../../../../domain/rules/remark-sanitize.rules';
import {
  isSoundcloudUrl,
  isSpotifyUrl,
  isYoutubeUrl
} from '../../../../../domain/rules/link-embed.rules';
import { APP_TRANSLATE_IMPORTS } from '../../../../../../../core/i18n';
import { ChatImageProxyFallbackDirective } from '../../../../chat-image-proxy-fallback.directive';
import { ChatSoundcloudEmbedComponent } from '../chat-soundcloud-embed/chat-soundcloud-embed.component';
import { ChatSpotifyEmbedComponent } from '../chat-spotify-embed/chat-spotify-embed.component';
import { ChatYoutubeEmbedComponent } from '../chat-youtube-embed/chat-youtube-embed.component';
import {
  CustomEmojiService,
  getCustomEmojiIdFromMarkdownAlt,
  getCustomEmojiLabelFromMarkdownAlt,
  isCustomEmojiMarkdownAlt,
  isCustomEmojiOnlyMessage,
  isSingleUnicodeEmojiOnlyMessage,
  replaceCustomEmojiMessageTokens,
  splitTextIntoEmojiSegments
} from '../../../../../../custom-emoji';

const PRISM_LANGUAGE_ALIASES: Record<string, string> = {
  cs: 'csharp',
  html: 'markup',
  js: 'javascript',
  md: 'markdown',
  plain: 'none',
  plaintext: 'none',
  py: 'python',
  sh: 'bash',
  shell: 'bash',
  svg: 'markup',
  text: 'none',
  ts: 'typescript',
  xml: 'markup',
  yml: 'yaml',
  zsh: 'bash'
};
const KLIPY_MEDIA_URL_PATTERN = /^(?:https?:)?\/\/(?:[^/]+\.)?klipy\.com/i;
const MERMAID_LINE_BREAK_PATTERN = /\r\n?/g;
const REMARK_PROCESSOR = unified().use(remarkParse)
  .use(remarkGfm)
  .use(remarkBreaks)
  .use(remarkStripDangerousContent());

@Component({
  selector: 'app-chat-message-markdown',
  standalone: true,
  imports: [
    CommonModule,
    RemarkModule,
    MermaidComponent,
    ChatImageProxyFallbackDirective,
    ChatSpotifyEmbedComponent,
    ChatSoundcloudEmbedComponent,
    ChatYoutubeEmbedComponent,
    ...APP_TRANSLATE_IMPORTS
  ],
  templateUrl: './chat-message-markdown.component.html'
})
export class ChatMessageMarkdownComponent {
  private readonly customEmoji = inject(CustomEmojiService);

  readonly content = input.required<string>();
  readonly displayContent = computed(() => replaceCustomEmojiMessageTokens(this.content(), (id) => this.customEmoji.findEmoji(id)));
  readonly largeCustomEmoji = computed(() => isCustomEmojiOnlyMessage(this.content()));
  readonly largeUnicodeEmoji = computed(() => isSingleUnicodeEmojiOnlyMessage(this.content()));
  readonly remarkProcessor = REMARK_PROCESSOR;
  readonly splitTextIntoEmojiSegments = splitTextIntoEmojiSegments;

  shouldRenderLargeCustomEmoji(url?: string): boolean {
    return this.isCustomEmojiDataUrl(url) && this.largeCustomEmoji();
  }

  getCustomEmojiAlt(alt?: string): string {
    return getCustomEmojiLabelFromMarkdownAlt(alt);
  }

  isCustomEmojiMarkdownImage(alt?: string): boolean {
    return isCustomEmojiMarkdownAlt(alt);
  }

  getCustomEmojiId(alt?: string): string | null {
    return getCustomEmojiIdFromMarkdownAlt(alt);
  }

  getMermaidCode(code?: string): string {
    return (code ?? '').replace(MERMAID_LINE_BREAK_PATTERN, '\n').trim();
  }

  isKlipyMediaUrl(url?: string): boolean {
    if (!url)
      return false;

    return KLIPY_MEDIA_URL_PATTERN.test(url);
  }

  isCustomEmojiDataUrl(url?: string): boolean {
    return !!url && /^data:image\//i.test(url);
  }

  isYoutubeUrl(url?: string): boolean {
    return isYoutubeUrl(url);
  }

  isSpotifyUrl(url?: string): boolean {
    return isSpotifyUrl(url);
  }

  isSoundcloudUrl(url?: string): boolean {
    return isSoundcloudUrl(url);
  }

  isMermaidCodeBlock(lang?: string): boolean {
    return this.normalizeCodeLanguage(lang) === 'mermaid';
  }

  getCodeBlockClass(lang?: string): string {
    return `language-${this.normalizeCodeLanguage(lang)}`;
  }

  private normalizeCodeLanguage(lang?: string): string {
    const normalized = (lang || '').trim().toLowerCase();

    if (!normalized)
      return 'none';

    return PRISM_LANGUAGE_ALIASES[normalized] ?? normalized;
  }
}
