import Component, {
    IComponent,
    IComponentOn,
    IComponentOptions,
    IComponentSelector,
} from "../core/Component";
import config from "../../config";
import { $, JDom } from "../core/JDom";

const selectors = {
    element: `.${config.prefix}-collapse`,
    wrapper: `.${config.prefix}-collapse-wrapper`,
    button: `.${config.prefix}-collapse-button`,
};

interface ICollapseSelector extends IComponentSelector {
    wrapper?: string;
    button?: string;
}

interface ICollapseOptions extends IComponentOptions {
    height?: number;
    duration?: number;
}

interface ICollapseOn extends IComponentOn {
    toggle?: (ctx?: Component) => void;
}

interface ICollapse extends IComponent {
    selectors?: ICollapseSelector;
    options?: ICollapseOptions;
    on?: ICollapseOn;
}

interface Collapse {
    selectors: ICollapseSelector;
    $wrapper: JDom;
    $button: JDom;
    options: ICollapseOptions;
    isActive: boolean;
    scrollHeight: number;
    on: ICollapseOn;
}

class Collapse extends Component {
    constructor(props: ICollapse = {}) {
        super({
            ...props,
            Component: Collapse,
            selectors: Object.assign(selectors, props.selectors || {}),
        });

        if (this.options && this.options.mount) {
            this.mount();
        }
    }

    mount() {
        if (!this.$element || this._mount || this.$element.attr("data-mount")) {
            return;
        }

        super.mount();

        this.options = Object.assign(
            {
                height: this.$element.dataset.height || 0,
                duration: this.$element.dataset.duration || 300,
            },
            this.options
        );

        this.handlers = {
            toggle: this.toggle.bind(this),
            resize: this.resize.bind(this),
        };

        this.on = Object.assign(
            {
                toggle: () => {},
            },
            this.on
        );

        this.$wrapper = $(this.$element).find(this.selectors.wrapper);
        this.$button = $(this.$element).find(this.selectors.button);

        this.isActive = false;
        this.scrollHeight = this.$wrapper.scrollHeight;

        this.addEvents();

        this.on.mount(this);
        this.emitter.emit("mount", this);
    }

    addEvents() {
        this.$wrapper.style.setProperty(
            "max-height",
            `${this.options.height}px`
        );
        this.$wrapper.style.setProperty(
            "transition",
            `all ease-in-out ${this.options.duration}ms`
        );

        this.$button.on("click", this.handlers.toggle);
        window.addEventListener("resize", this.handlers.resize);

        this.initButtonByHeight();
    }

    unmount() {
        super.unmount();

        this.$button.off("click", this.handlers.toggle, null);
        window.removeEventListener("resize", this.handlers.resize);

        this.$button.attr("data-mount", null);

        this.on.unmount(this);
        this.emitter.emit("unmount", this);
    }

    toggle() {
        this.scrollHeight = this.$wrapper.scrollHeight;

        if (this.isActive) {
            this.close();
        } else {
            this.open();
        }

        this.emitter.emit("toggle", this);
        this.on.toggle(this);
    }

    open() {
        this.$button.attr("data-active", "");
        this.$element.attr("data-active", "");
        this.$wrapper.attr("data-active", "");
        this.$wrapper.style.setProperty("max-height", `${this.scrollHeight}px`);

        this.isActive = true;
    }

    close() {
        this.$button.attr("data-active", null);
        this.$element.attr("data-active", null);
        this.$wrapper.attr("data-active", null);
        this.$wrapper.style.setProperty(
            "max-height",
            `${this.options.height}px`
        );

        this.isActive = false;
    }

    resize() {
        if (this.$wrapper) {
            this.scrollHeight = this.$wrapper.scrollHeight;

            if (this.isActive) {
                this.$wrapper.style.setProperty(
                    "max-height",
                    `${this.scrollHeight}px`
                );
            } else {
                this.$wrapper.style.setProperty(
                    "max-height",
                    `${this.options.height}px`
                );
            }
        }

        this.initButtonByHeight();
    }

    initButtonByHeight() {
        if (this.$button) {
            if (this.scrollHeight < this.options.height) {
                this.$button.attr("data-mount", null);
            } else {
                this.$button.attr("data-mount", "");
            }
        }
    }
}

export default Collapse;
