// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../../../core/common/common.js';
import * as SDK from '../../../core/sdk/sdk.js';
import type * as Protocol from '../../../generated/protocol.js';
import * as Trace from '../../../models/trace/trace.js';
import type * as Marked from '../../../third_party/marked/marked.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as PanelsCommon from '../../common/common.js';

import {MarkdownRendererWithCodeBlock} from './MarkdownRendererWithCodeBlock.js';

const {html} = Lit.StaticHtml;
const {until} = Lit.Directives;

export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBlock {
  constructor(
      private mainFrameId = '',
      private lookupEvent: (key: Trace.Types.File.SerializableKey) => Trace.Types.Events.Event | null = () => null) {
    super();
  }

  override templateForToken(token: Marked.Marked.MarkedToken): Lit.LitTemplate|null {
    if (token.type === 'link' && token.href.startsWith('#')) {
      if (token.href.startsWith('#node-')) {
        const nodeId = Number(token.href.replace('#node-', '')) as Protocol.DOM.BackendNodeId;

        return html`<span>${
            until(this.#linkifyNode(nodeId, token.text).then(node => node || token.text), token.text)}</span>`;
      }

      const event = this.lookupEvent(token.href.slice(1) as Trace.Types.File.SerializableKey);
      if (!event) {
        return html`${token.text}`;
      }

      let label = token.text;
      let title = '';
      if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
        title = event.args.data.url;
      } else {
        label += ` (${event.name})`;
      }

      // eslint-disable-next-line @devtools/no-a-tags-in-lit
      return html`<a href="#" draggable=false .title=${title} @click=${(e: Event) => {
        e.stopPropagation();
        void Common.Revealer.reveal(new SDK.TraceObject.RevealableEvent(event));
      }}>${label}</a>`;
    }

    return super.templateForToken(token);
  }

  // Taken from front_end/panels/timeline/components/insights/NodeLink.ts
  // Would be nice to move the above component to somewhere that allows the AI
  // Assistance panel to also use it.
  async #linkifyNode(backendNodeId: Protocol.DOM.BackendNodeId, label: string): Promise<Lit.LitTemplate|undefined> {
    if (backendNodeId === undefined) {
      return;
    }

    const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
    const domModel = target?.model(SDK.DOMModel.DOMModel);
    if (!domModel) {
      return undefined;
    }
    const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([backendNodeId]));
    const node = domNodesMap?.get(backendNodeId);
    if (!node) {
      return;
    }

    if (node.frameId() !== this.mainFrameId) {
      return;
    }

    const linkedNode = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(node, {textContent: label});
    return linkedNode;
  }
}
