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

import {assertNotNullOrUndefined} from '../../../../core/platform/platform.js';
import * as SDK from '../../../../core/sdk/sdk.js';
import type * as Protocol from '../../../../generated/protocol.js';
import * as Formatter from '../../../../models/formatter/formatter.js';
import * as CodeMirror from '../../../../third_party/codemirror.next/codemirror.next.js';
import * as CodeHighlighter from '../../../../ui/components/code_highlighter/code_highlighter.js';
import * as LegacyWrapper from '../../../../ui/components/legacy_wrapper/legacy_wrapper.js';
import * as RenderCoordinator from '../../../../ui/components/render_coordinator/render_coordinator.js';
import * as TextEditor from '../../../../ui/components/text_editor/text_editor.js';
import type * as UI from '../../../../ui/legacy/legacy.js';
import * as Lit from '../../../../ui/lit/lit.js';

import ruleSetDetailsViewStylesRaw from './RuleSetDetailsView.css.js';

// TODO(crbug.com/391381439): Fully migrate off of constructed style sheets.
const ruleSetDetailsViewStyles = new CSSStyleSheet();
ruleSetDetailsViewStyles.replaceSync(ruleSetDetailsViewStylesRaw.cssContent);

const {html} = Lit;

type RuleSet = Protocol.Preload.RuleSet;

const codeMirrorJsonType = await CodeHighlighter.CodeHighlighter.languageFromMIME('application/json');

export type RuleSetDetailsViewData = RuleSet|null;

export class RuleSetDetailsView extends LegacyWrapper.LegacyWrapper.WrappableComponent<UI.Widget.VBox> {
  readonly #shadow = this.attachShadow({mode: 'open'});
  #data: RuleSetDetailsViewData = null;
  #shouldPrettyPrint: boolean = true;
  #editorState?: CodeMirror.EditorState;

  connectedCallback(): void {
    this.#shadow.adoptedStyleSheets = [ruleSetDetailsViewStyles];
  }

  set data(data: RuleSetDetailsViewData) {
    this.#data = data;
    void this.#render();
  }

  set shouldPrettyPrint(shouldPrettyPrint: boolean) {
    this.#shouldPrettyPrint = shouldPrettyPrint;
  }

  async #render(): Promise<void> {
    await RenderCoordinator.write('RuleSetDetailsView render', async () => {
      if (this.#data === null) {
        Lit.render(Lit.nothing, this.#shadow, {host: this});
        return;
      }

      const sourceText = await this.#getSourceText();

      // Disabled until https://crbug.com/1079231 is fixed.
      // clang-format off
      Lit.render(html`
        <div class="content">
          <div class="ruleset-header" id="ruleset-url">${this.#data?.url || SDK.TargetManager.TargetManager.instance().inspectedURL()}</div>
          ${this.#maybeError()}
        </div>
        <div class="text-ellipsis">
          ${this.#renderSource(sourceText)}
        </div>
      `, this.#shadow, {host: this});
      // clang-format on
    });
  }

  // TODO(https://crbug.com/1425354): Support i18n.
  #maybeError(): Lit.LitTemplate {
    assertNotNullOrUndefined(this.#data);

    if (this.#data.errorMessage === undefined) {
      return Lit.nothing;
    }

    // Disabled until https://crbug.com/1079231 is fixed.
    // clang-format off
    return html`
      <div class="ruleset-header">
        <devtools-icon
          .data=${{
            iconName: 'cross-circle',
            color: 'var(--icon-error)',
            width: '16px',
            height: '16px',
          }}>
        </devtools-icon>
        <span id="error-message-text">${this.#data.errorMessage}</span>
      </div>
    `;
            // clang-format on
  }

  #renderSource(sourceText: string): Lit.LitTemplate {
    this.#editorState = CodeMirror.EditorState.create({
      doc: sourceText,
      extensions: [
        TextEditor.Config.baseConfiguration(sourceText || ''),
        CodeMirror.lineNumbers(),
        CodeMirror.EditorState.readOnly.of(true),
        codeMirrorJsonType as CodeMirror.Extension,
        CodeMirror.syntaxHighlighting(CodeHighlighter.CodeHighlighter.highlightStyle),
      ],
    });
    // Disabled until https://crbug.com/1079231 is fixed.
    // clang-format off
    // TODO(https://crbug.com/1425354): Add Raw button.
    return html`
      <devtools-text-editor .style.flexGrow=${'1'} .state=${
        this.#editorState
      }></devtools-text-editor>
    `;
    // clang-format on
  }

  async #getSourceText(): Promise<string> {
    if (this.#shouldPrettyPrint && this.#data?.sourceText !== undefined) {
      const formattedResult =
          await Formatter.ScriptFormatter.formatScriptContent('application/json', this.#data.sourceText);
      return formattedResult.formattedContent;
    }

    return this.#data?.sourceText || '';
  }
}

customElements.define('devtools-resources-rulesets-details-view', RuleSetDetailsView);

declare global {
  interface HTMLElementTagNameMap {
    'devtools-resources-rulesets-details-view': RuleSetDetailsView;
  }
}
