import CSS from "csstype";
import {
    evaluateSpringyValueInterpolator, interpolateSpringyValueInterpolatables,
    SpringyValueInterpolatables,
    SpringyValueInterpolate,
    SpringyValueInterpolateds,
    SpringyValues
} from "./SpringyValueHook";
import {isDefined} from "./type_check";

export interface ResourceBarColors {
    filledColor: CSS.Property.Color
    toFillColor: CSS.Property.Color
    toEmptyColor: CSS.Property.Color
    emptiedColor: CSS.Property.Color
}

export function resourceGradient(
    {filledColor, toFillColor, toEmptyColor, emptiedColor}: ResourceBarColors,
    {displayedValue, recentValue, newValue, maxValue}: SpringyValues,
    direction: string): string {
    const effectiveMax = isDefined(maxValue) && maxValue !== 0 ? maxValue : Number.POSITIVE_INFINITY
    const currentStop = Math.min(Math.max(100 * displayedValue / effectiveMax, 0), 100)
    const currentSoftEdgeLeft = Math.min(Math.max(currentStop - 0.2, 0), 100)
    const currentSoftEdgeRight = Math.min(Math.max(currentStop + 0.2, 0), 100)

    const endFillingStop = Math.min(Math.max(100 * recentValue / effectiveMax, 0), currentStop)
    const midFillingStop = Math.min(Math.max(100 * newValue / effectiveMax, endFillingStop), currentStop)

    const endFadingStop = Math.min(Math.max(100 * recentValue / effectiveMax, currentStop), 100)
    const midFadingStop =
        Math.min(Math.max(100 * newValue / effectiveMax, currentStop), endFadingStop)

    const layers = []
    if (currentStop === 100) {
        layers.unshift(filledColor)
    } else {
        layers.unshift(emptiedColor)
        if (currentStop > 0) {
            layers.unshift(`linear-gradient(${direction}, ${filledColor} 0% ${currentSoftEdgeLeft.toFixed(4)}%, transparent ${currentSoftEdgeRight.toFixed(4)}% 100%)`)
        }
    }
    if (endFillingStop !== currentStop || midFillingStop !== currentStop) {
        layers.unshift(`linear-gradient(${direction}, transparent 0% ${endFillingStop.toFixed(4)}%, ${toFillColor} ${midFillingStop.toFixed(4)}% ${currentSoftEdgeLeft.toFixed(4)}%, transparent ${currentSoftEdgeRight.toFixed(4)}% 100%)`)
    }
    if (endFadingStop !== currentStop || midFadingStop !== currentStop) {
        layers.unshift(`linear-gradient(${direction}, transparent 0% ${currentSoftEdgeLeft.toFixed(4)}%, ${toEmptyColor} ${currentSoftEdgeRight.toFixed(4)}% ${midFadingStop.toFixed(4)}%, transparent ${endFadingStop.toFixed(4)}% 100%)`)
    }
    return layers.join(", ")
}

export interface ResourceBarStyles extends CSS.Properties {
    foreground?: CSS.Properties["background"]
    barDirection?: string
    barColors?: ResourceBarColors
}

export const DEFAULT_BAR_COLORS: ResourceBarColors = {
    emptiedColor: 'black',
    filledColor: 'limegreen',
    toEmptyColor: 'red',
    toFillColor: 'cyan',
} as const

export const DEFAULT_BAR_DIRECTION: string = "to right"

export function evaluateResourceBarStyles(barStyle: SpringyValueInterpolatables<ResourceBarStyles>, interpolate: SpringyValueInterpolate) {
    const intermediate: SpringyValueInterpolatables<ResourceBarStyles> = Object.assign({}, barStyle)
    delete intermediate.background
    delete intermediate.foreground
    delete intermediate.barColors
    delete intermediate.barDirection
    intermediate.background = (v: SpringyValues) => [
            evaluateSpringyValueInterpolator(barStyle["foreground"], v) as string | undefined,
            resourceGradient(
                evaluateSpringyValueInterpolator(barStyle["barColors"], v) ?? DEFAULT_BAR_COLORS, v,
                evaluateSpringyValueInterpolator(barStyle["barDirection"], v) ?? DEFAULT_BAR_DIRECTION),
            evaluateSpringyValueInterpolator(barStyle["background"], v) as string | undefined
        ].filter((s) => !!s).join(', ')
    return interpolateSpringyValueInterpolatables(intermediate as SpringyValueInterpolateds<CSS.Properties>, interpolate)
}