import * as React from 'react'
import * as cx from 'classnames'
import { connect } from 'react-redux'

import { forceArray } from '../../utils'
import { StylableComponent } from '../theme'
import { Column } from '../flex'

import {
    accordionExpand,
    accordionCollapse,
    accordionDestroy,
} from './actions'

import { AccordionProps, AccordionComponentProps } from './interfaces'
import { getAccordionById } from './selectors'

const styles = require('../../../src/components/accordion/styles.scss')

class Component extends StylableComponent<AccordionComponentProps> {
    public componentWillMount() {
        if (this.props.firstOpen) {
            const firstChild: JSX.Element = (forceArray(this.props.children)[0] as JSX.Element)
            this.props.accordionExpand(this.props.id, (firstChild.key as string))
        } else {
            this.props.accordionCollapse(this.props.id)
        }
    }

    public componentWillUnmount() {
        this.props.accordionDestroy(this.props.id)
    }

    public render(): JSX.Element | null {
        if (!this.props.accordion) return null
        return (
            <Column className={cx(styles.container, {
                [styles.fullWidth]: this.props.fullWidth,
            })}>{this.getChildNodes()}</Column>
        )
    }

    private getChildNodes(): JSX.Element[] {
        return forceArray(this.props.children)
            .map((child: JSX.Element) => this.getChildNode(child))
    }

    private getChildNode(child: JSX.Element): JSX.Element {
        if (!child
            || child.key === null
            || child.key === undefined
            || typeof child.key === 'number') {
            throw new Error('Accordion children MUST be a JSX element with a string key')
        }

        return React.cloneElement(child, {
            expanded: this.props.accordion.key === child.key,
            onToggle: this.mkHandleClick(child.key),
        })
    }

    private mkHandleClick = (key: string) =>
        (e: React.SyntheticEvent<any>): void => {
            e.preventDefault()
            if (key === this.props.accordion.key) {
                this.props.accordionCollapse(this.props.id)
            } else {
                this.props.accordionExpand(this.props.id, key)
            }
        }
}

const mapStateToProps = (state: any, ownProps: AccordionProps) => ({
    ...ownProps,
    accordion: getAccordionById(state, ownProps.id),
})

const mapDispatchToProps = { accordionExpand, accordionCollapse, accordionDestroy }

export const Accordion = connect(mapStateToProps, mapDispatchToProps)(Component)