'use strict';

import React, {Component} from "react";
import jsonLogic from 'json-logic-js';

// https://stackoverflow.com/a/70511311
const trueTypeOf = (obj) => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();

class Radio extends Component {
    constructor(props) {
        super(props);
        // Initialize the state object with the initial values from the props
        this.state = {
            variant: props.outvar in props.data ? props.data[props.outvar] : props.variants[0],
        };

        // Bind the event handler to this
        this.handleClick = this.handleClick.bind(this);
        this.props.target.construct(this.props.outvar, this.state.variant);
    }

    componentWillUnmount() {
        this.props.target.unmount(this.props.outvar);
    }

    handleClick(variant) {
        // Update the state object with the new value for outvar
        this.setState({
            ...this.state,
            variant: variant
        });
        this.props.target.update(this.props.outvar, variant);
    }

    render() {
        let key = this.props.id + this.props.outvar;
        return (
            <div className="shop-radio" key={this.props.id}>
                <div>{this.props.title}</div>
                {this.props.variants.map((variant, _) => (
                    <div className="form-check" key={key + variant}>
                        <input
                            className="form-check-input"
                            type="radio"
                            name={key}
                            id={key + variant}
                            checked={this.state.variant === variant}
                            onClick={() => this.handleClick(variant)}
                            onChange={() => this.handleClick(variant)}
                        />
                        <label className="form-check-label" htmlFor={key + variant}>
                            {variant}
                        </label>
                    </div>
                ))}
            </div>
        );
    }
}

function RadioWrapper(target, id, data, {title, variants, outvar}) {
    return <Radio target={target} title={title} variants={variants} outvar={outvar} key={id} id={id} data={data}/>;
}

class Switch extends Component {
    constructor(props) {
        super(props);
        // Initialize the state object with the initial values from the props
        this.state = {
            checked: props.outvar in props.data ? props.data[props.outvar] : !!(props.fallback)
        };

        // Bind the event handler to this
        this.handleClick = this.handleClick.bind(this);
        this.props.target.construct(this.props.outvar, this.state.checked);
    }

    componentWillUnmount() {
        this.props.target.unmount(this.props.outvar);
    }

    handleClick() {
        // Update the state object with the new value for outvar
        let new_checked = !this.state.checked;
        this.setState({
            checked: new_checked
        });
        this.props.target.update(this.props.outvar, new_checked);
    }

    render() {
        let key = this.props.id + this.props.outvar;
        return (
            <div className="shop-switch" key={this.props.id}>
                <div className="form-check form-switch" key={key}>
                    <input
                        className="form-check-input"
                        type="checkbox"
                        role="switch"
                        id={key}
                        checked={this.state.checked}
                        onClick={this.handleClick}
                        onChange={this.handleClick}
                    />
                    <label className="form-check-label" htmlFor={key}>
                        {this.props.title}
                    </label>
                </div>
            </div>
        );
    }
}

function SwitchWrapper(target, id, data, {title, fallback, outvar}) {
    return <Switch target={target} title={title} fallback={fallback} outvar={outvar} key={id} id={id} data={data}/>;
}


class Line extends Component {
    constructor(props) {
        super(props);
        // Initialize the state object with the initial values from the props
        this.state = {
            text: props.outvar in props.data ? props.data[props.outvar] : (props.fallback ? props.fallback : "")
        };
        // Bind the event handler to this
        this.handleClick = this.handleClick.bind(this);
        this.props.target.construct(this.props.outvar, this.state.text);
    }

    componentWillUnmount() {
        this.props.target.unmount(this.props.outvar);
    }

    handleClick(element) {
        let text = element.target.value;
        this.setState({
            text: text
        });
        this.props.target.update(this.props.outvar, text);
    }

    render() {
        let key = this.props.id + this.props.outvar;
        return (
            <div className="shop-line" key={this.props.id}>
                <label htmlFor={key} className="form-label">{this.props.title}: </label>
                <input type="text" className="form-control form-control-sm" id={key} onChange={this.handleClick}
                       value={this.state.text}/>
            </div>
        );
    }
}

function LineWrapper(target, id, data, {title, fallback, outvar}) {
    return <Line target={target} title={title} fallback={fallback} outvar={outvar} key={id} id={id} data={data}/>;
}

class SwitchLine extends Component {
    constructor(props) {
        super(props);
        // Initialize the state object with the initial values from the props
        this.state = {
            text: props.outvar in props.data ? props.data[props.outvar].text : (props.fallback ? props.fallback.text : ""),
            checked: props.outvar in props.data ? props.data[props.outvar].checked : (props.fallback ? props.fallback.checked : false)
        };
        // Bind the event handler to this
        this.handleText = this.handleText.bind(this);
        this.handleCheck = this.handleCheck.bind(this);
        this.props.target.construct(this.props.outvar, this.state);
    }

    componentWillUnmount() {
        this.props.target.unmount(this.props.outvar);
    }

    handleText(element) {
        let new_state = {
            ...this.state,
            text: element.target.value
        }
        this.setState(new_state);
        this.props.target.update(this.props.outvar, new_state);
    }

    handleCheck() {
        // Update the state object with the new value for outvar
        let new_state = {
            ...this.state,
            checked: !this.state.checked
        }
        this.setState(new_state);
        this.props.target.update(this.props.outvar, new_state);
    }

    render() {
        let key = this.props.id + this.props.outvar;
        return (
            <div className="shop-switch-line" key={this.props.id}>
                <div className="form-check form-switch" key={key}>
                    <input
                        className="form-check-input"
                        type="checkbox"
                        role="switch"
                        id={key + "switch"}
                        checked={this.state.checked}
                        onClick={this.handleCheck}
                        onChange={this.handleCheck}
                    />
                    <label className="form-check-label" htmlFor={key + "switch"}>
                        {this.props.title}
                    </label>
                </div>
                <input type="text" className="form-control form-control-sm" id={key + "line"} onChange={this.handleText}
                       value={this.state.text} disabled={!this.state.checked}/>
            </div>
        );
    }
}

function SwitchLineWrapper(target, id, data, {title, fallback, outvar}) {
    return <SwitchLine target={target} title={title} fallback={fallback} outvar={outvar} key={id} id={id} data={data}/>;
}


function UnimplementedComponent(type, id) {
    //console.error("Missing component with type:", type)
    return <div key={type + id} style={{background: "red"}}>UNIMPLEMENTED</div>
}

const componentsList = {
    "Radio": RadioWrapper,
    "Switch": SwitchWrapper,
    "Line": LineWrapper,
    "SwitchLine": SwitchLineWrapper,
    "Default": UnimplementedComponent,
};


export default function ProcessOptions({options, data, target, id}) {
    let options_t = trueTypeOf(options);

    if (options_t === "array") {
        return Array.from(
            options.map((option_item, i) => ProcessOptions({
                options: option_item,
                data: data,
                target: target,
                id: id + i
            }))
        );
    } else if (options_t === "object") {
        if (
            trueTypeOf(options.type) === "string" &&
            trueTypeOf(options.args) === "object"
        ) {
            if (options.type in componentsList) {
                return componentsList[options.type](target, id + options.type, data, options.args);
            } else {
                return componentsList["Default"](options.type, id + "missing");
            }
        } else {
            return ProcessOptions({options: jsonLogic.apply(options, data), data: data, target: target, id: id});
        }
    }
}