import path from 'path';
import {
  DecorationOptions,
  ExtensionContext,
  Position,
  Range,
  TextEditor,
  TextEditorDecorationType,
  ThemeColor,
  window,
} from 'vscode';
import { CsvEntry } from '../model';
import { isValidColorDefinition } from './editor-utils';
import { rangesFromStringDefinition } from './workspace-util';

export const EDITOR_MAX_LETTER = 1024;

export class Decorations {
  constructor(private readonly context: ExtensionContext) {}

  readonly decorationDeclarationType = window.createTextEditorDecorationType({
    isWholeLine: false,
    opacity: '0.9',
    borderWidth: '1px',
    borderColor: '#0f0f0f',
    borderStyle: 'none none dashed none',
    dark: {
      borderColor: '#F6F6F6',
    },
  });

  readonly commentDecorationType = window.createTextEditorDecorationType({
    isWholeLine: true,
    after: {
      contentIconPath: this.context.asAbsolutePath(path.join('dist', 'speech-bubble-light.svg')),
      margin: '5px',
    },
    dark: {
      after: {
        contentIconPath: this.context.asAbsolutePath(path.join('dist', 'speech-bubble-dark.svg')),
      },
    },
  });

  /**
   * Highlight a matching review comment with decorations an underline decoration
   *
   * @param csvEntries The selection to highlight
   * @param editor The editor to work on
   * @return all highlighting decorations
   */
  underlineDecoration(csvEntries: CsvEntry[], editor: TextEditor): void {
    const decorationOptions: DecorationOptions[] = [];

    // build decoration options for each comment block
    csvEntries.forEach((entry) => {
      // iterate over multi-selections
      rangesFromStringDefinition(entry.lines).forEach((range: Range) => {
        decorationOptions.push({ range });
      });
    });

    editor.setDecorations(this.decorationDeclarationType, decorationOptions);
  }

  /**
   * Highlight a matching review comment with an icon next to the start of the selection on the right
   *
   * @param csvEntries The selection to highlight
   * @param editor The editor to work on
   * @return all highlighting decorations
   */
  commentIconDecoration(csvEntries: CsvEntry[], editor: TextEditor): void {
    const decorationOptions: DecorationOptions[] = [];

    // build decoration options for each comment block
    csvEntries.forEach((entry) => {
      // iterate over multi-selections
      rangesFromStringDefinition(entry.lines).forEach((range: Range) => {
        decorationOptions.push({
          range: new Range(
            new Position(range.start.line, EDITOR_MAX_LETTER),
            new Position(range.start.line, EDITOR_MAX_LETTER),
          ),
        });
      });
    });
    editor.setDecorations(this.commentDecorationType, decorationOptions);
  }

  clear(editor: TextEditor) {
    this.underlineDecoration([], editor);
    this.commentIconDecoration([], editor);
  }
}

/**
 * Highlight a selection in an editor
 *
 * @param selections The selection to highlight
 * @param editor The editor to work on
 * @return TextEditorDecorationType
 */
export const colorizedBackgroundDecoration = (
  selections: Range[],
  editor: TextEditor,
  color: string,
): TextEditorDecorationType => {
  const backgroundColorDefaultID = 'codereview.code.selection.background';
  const backgroundColorDefault = new ThemeColor(backgroundColorDefaultID);
  let backgroundColor: string | ThemeColor;
  if (color === backgroundColorDefaultID) {
    backgroundColor = backgroundColorDefault;
  } else if (isValidColorDefinition(color)) {
    backgroundColor = color;
  } else {
    console.log(`Invalid background color definition: ${color}`);
    backgroundColor = backgroundColorDefault;
  }

  const decoration = window.createTextEditorDecorationType({
    backgroundColor: backgroundColor,
  });
  editor.setDecorations(decoration, selections);

  return decoration;
};