/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { SpApplication } from '../SpApplication';
import { Rect } from '../component/trace/timer-shaft/Rect';
import { warn } from '../../log/Log';
import { BaseStruct, drawString } from '../database/ui-worker/ProcedureWorkerCommon';

const padding: number = 1;
const rectHeight = 20;

const lightBlue = {
  r: 82,
  g: 145,
  b: 255,
  a: 0.9,
};
const lightGreen = {
  r: 132,
  g: 200,
  b: 112,
  a: 0.9,
};
const purple = {
  r: 147,
  g: 112,
  b: 219,
  a: 0.9,
};

export class ChartStruct extends BaseStruct {
  static hoverFuncStruct: ChartStruct | undefined;
  static selectFuncStruct: ChartStruct | undefined;
  static lastSelectFuncStruct: ChartStruct | undefined;
  static tempSelectStruct: ChartStruct | undefined;
  isDraw = false; // 是否绘制,太小的不绘制
  depth: number = 0;
  symbol: string = '';
  lib: string = '';

  id?: string;
  eventType?: string;
  parentId?: string;
  self?: string; // only perf
  eventPercent?: string; // only perf
  title?: string;

  size: number = 0; // 实际size
  count: number = 0; // 实际count
  eventCount: number = 0;
  dur: number = 0; // 实际dur
  //搜索后会根据搜索匹配的函数的值赋值给parent
  searchSize: number = 0; //
  searchCount: number = 0;
  searchDur: number = 0;
  searchEventCount: number = 0;
  //点击绘制的size在搜索的基础上,赋值给parent
  drawSize: number = 0;
  drawCount: number = 0;
  drawDur: number = 0;
  drawEventCount: number = 0;

  parent: ChartStruct | undefined;
  children: Array<ChartStruct> = [];
  percent: number = 0; // 0 - 1 该node所占整体的百分比
  addr: string = '';
  isReverseFilter:boolean = false;
  isSearch: boolean = false;
  isChartSelect: boolean = false; // 是否为点选的调用链
  isChartSelectParent: boolean = false; // 用来显示灰色
  tsArray: Array<number> = [];
  countArray: Array<number> = [];
  durArray: Array<number> = [];
  isThread: boolean = false;
  isProcess: boolean = false;
  isJsStack: boolean = false;
  isAsyncStack: boolean = false;
  sourceFile: string = '';
  lineNumber: Set<number> = new Set<number>();
}

export enum ChartMode {
  Byte, // Native Memory
  Count, // Perf
  Duration, // eBpf
  EventCount, //cycles
}

export function setFuncFrame(node: ChartStruct, canvasFrame: Rect, total: number, mode: ChartMode): void {
  if (!node.frame) {
    node.frame = new Rect(0, 0, 0, 0);
  }
  // filter depth is 0
  if (node.parent) {
    let idx = node.parent.children.indexOf(node);
    if (idx === 0) {
      node.frame!.x = node.parent.frame!.x;
    } else {
      // set x by left frame. left frame is parent.children[idx - 1]
      node.frame.x = node.parent.children[idx - 1].frame!.x + node.parent.children[idx - 1].frame!.width;
    }
    if (node.parent?.isChartSelect && !node.isChartSelect) {
      node.frame!.width = 0;
    } else {
      switch (mode) {
        case ChartMode.Byte:
          node.frame!.width = Math.floor(((node.drawSize || node.size) / total) * canvasFrame.width);
          break;
        case ChartMode.Count:
          node.frame!.width = Math.floor(((node.drawCount || node.count) / total) * canvasFrame.width);
          break;
        case ChartMode.Duration:
          node.frame!.width = Math.floor(((node.drawDur || node.dur) / total) * canvasFrame.width);
          break;
        case ChartMode.EventCount:
          node.frame!.width = Math.floor(((node.drawEventCount || node.eventCount) / total) * canvasFrame.width);
          break;
        default:
          warn('not match ChartMode');
      }
    }

    node.frame!.y = node.parent.frame!.y + rectHeight;
    node.frame!.height = rectHeight;
  }
}

/**
 * draw rect
 * @param canvasCtx CanvasRenderingContext2D
 * @param node rect which is need draw
 * @param percent function size or count / total size or count
 */
export function draw(canvasCtx: CanvasRenderingContext2D, node: ChartStruct): void {
  let spApplication = <SpApplication>document.getElementsByTagName('sp-application')[0];
  if (!node.frame) {
    return;
  }
  //主体
  const drawHeight = rectHeight - padding * 2; //绘制方块上下留一个像素
  if (node.depth === 0 || (node.isChartSelectParent && node !== ChartStruct.selectFuncStruct)) {
    canvasCtx.fillStyle = `rgba(${lightBlue.g}, ${lightBlue.g}, ${lightBlue.g}, ${lightBlue.a})`;
  } else {
    if (node.isSearch) {
      canvasCtx.fillStyle = `rgba(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b}, ${lightBlue.a})`;
    } else {
      if (node.isJsStack) {
        canvasCtx.fillStyle = `rgba(${lightGreen.r}, ${lightGreen.g}, ${lightGreen.b}, ${lightGreen.a})`;
      } else {
        if (node.isAsyncStack) {
          canvasCtx.fillStyle = `rgba(${purple.r}, ${purple.g}, ${purple.b}, ${purple.a})`;
        } else {
          canvasCtx.fillStyle = getHeatColor(node.percent);
        }
      }
    }
  }
  canvasCtx.fillRect(node.frame.x, node.frame.y, node.frame.width, drawHeight);
  //边框
  canvasCtx.lineWidth = 0.4;
  if (isHover(node)) {
    if (spApplication.dark) {
      canvasCtx.strokeStyle = '#fff';
    } else {
      canvasCtx.strokeStyle = '#000';
    }
  } else {
    if (spApplication.dark) {
      canvasCtx.strokeStyle = '#000';
    } else {
      canvasCtx.strokeStyle = '#fff';
    }
  }
  canvasCtx.strokeRect(node.frame.x, node.frame.y, node.frame.width - canvasCtx.lineWidth, drawHeight);
  //文字
  if (node.frame.width > 10) {
    if (node.percent > 0.6 || node.isSearch) {
      canvasCtx.fillStyle = '#fff';
    } else {
      canvasCtx.fillStyle = '#000';
    }
    drawString(canvasCtx, splitSymbol(node), 5, node.frame, node);
  }
  node.isDraw = true;
}

export function splitSymbol(node: ChartStruct): string {
  if (node.depth === 0 || node.isProcess || node.isThread) {
    return node.symbol;
  }
  return node.symbol.split(' (')[0];
}

/**
 * 火焰图颜色计算,根据每个node占总大小的百分比调整
 * @param widthPercentage 百分比
 * @returns rbg
 */
function getHeatColor(widthPercentage: number): string {
  return `rgba(
    ${Math.floor(245 + 10 * (1 - widthPercentage))},
    ${Math.floor(110 + 105 * (1 - widthPercentage))},
    ${100},
    0.9)`;
}

function isHover(data: ChartStruct): boolean {
  return ChartStruct.hoverFuncStruct === data;
}