<template>
  <div class="trace-view-container" :class="trace ? '' : 'trace-view-container--no-trace'">
    <div class="trace-view-header">
      <h3 class="sub-header">{{ title }} <br><span class="trace-view-message" v-if="showMessage">{{ message }}</span>
      </h3>
      <icon-button icon="x" @click="$emit('close')"></icon-button>
    </div>
    <div v-if="trace" class="trace-view">
      <div class="trace-view-exception">{{ exception }}</div>
      <div :class="highlightClasses(traceItem)" v-for="traceItem of trace">at {{ fullClassName(traceItem) }} (<span
          class="trace-view-file">{{ fileName(traceItem) }}</span>)
      </div>
    </div>
    <div v-if="traceCombined" class="trace-view">
      <div class="trace-view-exception">{{ traceCombinedException }}</div>
      <div class="trace-item" v-for="traceItem of traceCombinedItems">
        <div v-html="highlightFilenames(traceItem)"/>
      </div>
    </div>
  </div>
</template>

<script>

import BasicButton from "@/components/UI/BasicButton.vue";
import IconButton from "@/components/UI/IconButton.vue";
import {PhWarning} from "@phosphor-icons/vue";

export default {
  name: "TraceView",
  components: {PhWarning, IconButton, BasicButton},
  emits: ['close'],
  props: {
    error: {
      type: Object,
      required: true
    }
  },
  computed: {
    traceCombined() {
      return this.error.traceCombined;
    },
    traceCombinedException() {
      return this.error.traceCombined?.split('\n')[0];
    },
    traceCombinedItems() {
      return this.error.traceCombined?.split('\n').slice(1);
    },
    trace() {
      return this.error.trace;
    },
    exception() {
      return this.error.code;
    },
    title() {
      return this.error.title;
    },
    code() {
      return this.error.code;
    },
    showMessage() {
      return this.error.message !== this.error.trace?.errorMessage;
    },
    message() {
      return this.error.message;
    },

  },
  methods: {
    highlightClasses(traceItem) {
      return traceItem.className?.includes('de.avatic.lcc') ? 'highlight-trace-item' : 'trace-item';
    },
    fullClassName(traceItem) {
      return `${traceItem.className}.${traceItem.methodName}`;
    },
    fileName(traceItem) {
      return `${traceItem.fileName}:${traceItem.lineNumber}`;
    },
    highlightFilenames(text) {
      if (!text) return text;

      // Regex to match file paths ending with .vue or .js
      // This will match paths like http://localhost:5173/src/pages/CalculationSingleEdit.vue
      const filePathRegex = /(https?:\/\/[^\s]+\/)?([^\/\s]+\.(vue|js))/g;

      return text.replace(filePathRegex, (match, path, filename) => {
        // If there's a path, keep it but only bold the filename
        if (path) {
          return `${path}<strong class="highlighted-filename">${filename}</strong>`;
        }
        // If it's just a filename, bold it
        return `<strong class="highlighted-filename">${filename}</strong>`;
      });
    }
  }
}
</script>

<style scoped>

@import url('https://fonts.googleapis.com/css2?family=Cal+Sans&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap');

.highlight-trace-item {

  color: #002F54;
  background-color: #F2F2F2;
  padding-left: 1.6rem;
}

.trace-item {
  padding-left: 1.6rem;
}

.trace-view {
  overflow: auto;
  font-family: Roboto Mono, monospace;
  font-size: 1.2rem;
  flex: 1;
  padding: 0 1.6rem;
}

.trace-view-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.trace-view-message {
  font-size: 1.2rem;
}

.trace-view-file {
  font-weight: 500;
  text-decoration: underline;
}

.trace-view-exception {


}

.trace-view-container {
  height: 90vh;
  width: 80vw;
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
}

.trace-view-container--no-trace {
  height: auto;
  width: auto;
}

</style>