<script setup>
import { watch } from 'vue';
import { toDateString } from 'src/filters';

const props = defineProps({
    value: { type: [String, Number, Boolean, Object], default: undefined },
});

const maxStrLen = 512;
let t = '';
let cssClass = '';
let type;
const updateValue = () => {
    type = typeof props.value;

    if (props.value == null) {
        t = '∅';
        cssClass = 'json-null';
    } else {
        cssClass = `json-${type}`;
        switch (type) {
            case 'number':
                if (Number.isInteger(props.value)) {
                    t = props.value.toString();
                } else {
                    t = (
                        Math.round((props.value + Number.EPSILON) * 1000) / 1000
                    ).toString();
                }
                break;
            case 'boolean':
                t = props.value ? '✓' : '✗';
                cssClass = `json-${props.value ? 'true' : 'false'}`;
                break;
            case 'string':
                t =
                    props.value.length <= maxStrLen
                        ? props.value
                        : props.value.substring(0, maxStrLen) + '...';
                break;
            case 'object':
                if (props.value instanceof Date) {
                    t = toDateString(props.value);
                } else {
                    t = props.value.toString();
                }
                break;
            default:
                t = props.value.toString();
        }
    }
};

watch(() => props.value, updateValue);

updateValue();
</script>

<template>
    <span
        :title="type === 'string' && props.value.length > maxStrLen ? props.value : ''"
        :class="{ [cssClass]: t !== '' }"
    >
        {{ t }}
    </span>
</template>

<style scoped>
.json-string {
    color: #d172cc;
}
.json-object {
    color: #d1a572;
}
.json-number {
    color: #85d0ff;
}
.json-true {
    color: #7dc489;
}
.json-false {
    color: #c74949;
}
.json-null {
    color: #cd7c7c;
    font-style: italic;
}
</style>
