import type {CardRenderer, CardRendererParameters} from "./CardRenderers";
import {getCardComponentData} from "./cards";
import {CardItemSecondaryValue} from "./CardItemSecondaryValue";
import {__} from "../globals";
import {Color} from "./Color";
import {CardItemMainValue} from "./CardItemMainValue";
import {get, isPlainObject} from "lodash";
import {isValidElement} from "react";
import {ComponentDataType, OfferData, TestableData} from "./store";


export class CardRendererFromCardComponentDataDecorator implements CardRenderer {
    public cardRenderer: CardRenderer;
    testableType: 'filter' | 'condition';
    private id: string;
    private partialId: string | undefined;
    private localData: object | undefined;

    constructor(cardRenderer: CardRenderer | undefined, testableType: ComponentDataType, id: string, partialId?: string, localData?: TestableData | OfferData) {
        this.cardRenderer = cardRenderer || this.getUnavailableCardRenderer(localData?.type);
        this.testableType = testableType;
        this.id = id;
        this.partialId = partialId;
        this.localData = localData;

        // Create a proxy to handle property access
        return new Proxy(this, {
            get: (target, prop, receiver) => {
                // If the property exists on the decorator, return it
                if (prop in target) {
                    return Reflect.get(target, prop, receiver);
                }

                // Otherwise forward to the cardRenderer
                return Reflect.get(target.cardRenderer, prop);
            }
        });
    }

    private getUnavailableCardRenderer(missingType?: string): CardRenderer {
        return {
            type: missingType || 'UnavailableComponent',
            icon: ({className}) => (
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className={className}>
                    <path fillRule="evenodd"
                          d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12ZM12 7.5a.75.75 0 0 1 .75.75v4.19a.75.75 0 0 1-1.5 0V8.25A.75.75 0 0 1 12 7.5Zm0 9a.938.938 0 1 0 0-1.876.938.938 0 0 0 0 1.876Z"
                          clipRule="evenodd"/>
                </svg>
            ),
            AboveComputedValue: () => __('Unavailable component'),
            ComputedValue: () => missingType || __('Not available'),
            BelowComputedValue: () => __('This component is currently unavailable.'),
        }
    }

    get icon() {
        return this?.cardRenderer?.icon;
    }

    get ComputedValue() {
        if (!this.cardRenderer.ComputedValue) {
            return
        }
        return (parameters: CardRendererParameters) => <CardItemMainValue color={parameters.color}>
            {this.cardRenderer.ComputedValue(this.getCardRendererParameters(parameters))}
        </CardItemMainValue>;
    }

    get AboveComputedValue() {
        return (parameters) => {
            let aboveComputedValueCache: any
            const getAboveComputedValue = () => {
                aboveComputedValueCache = this?.cardRenderer?.AboveComputedValue?.(this.getCardRendererParameters(parameters));
                return aboveComputedValueCache
            }

            const givenAboveComputedValue = getAboveComputedValue();

            const isObjectLiteral = isPlainObject(givenAboveComputedValue) && !isValidElement(givenAboveComputedValue);

            if (typeof this.cardRenderer.AboveComputedValue !== 'function' || givenAboveComputedValue === undefined || isObjectLiteral) {

                return <CardItemSecondaryValue
                    color={parameters.color} {...isObjectLiteral ? givenAboveComputedValue : {}}>
                    {
                        isObjectLiteral && givenAboveComputedValue.label ? givenAboveComputedValue.label :
                            getCardComponentData(this.testableType, this.cardRenderer.type!)?.name || __('Unavailable component')
                    }
                </CardItemSecondaryValue>

            }
            const aboveComputedValue = givenAboveComputedValue;

            if (aboveComputedValue) {
                if (typeof aboveComputedValue === 'string') {
                    return <CardItemSecondaryValue color={parameters.color}>
                        {aboveComputedValue}
                    </CardItemSecondaryValue>;
                }

                return aboveComputedValue;
            }
        };
    }

    get prefix() {
        return this.cardRenderer.prefix;
    }

    private getCardRendererParameters(parameters: CardRendererParameters) {
        return {
            ...parameters,
            ...{
                id: this.id,
                partialId: this.partialId,
                localData: this.localData,
            }
        };
    }
}
