import { Markdown } from '@signatu/common-lib';
import { Theme, WithStyles, withStyles } from '@signatu/styles';
import { ConsentActionType, ConsentConfig, ConsentEvent } from '@signatu/consent';
import { Policy, PolicyDataProcessing, PolicyElement } from '@signatu/policy';
import { PolicyLink } from '@signatu/policy-react';
import PropTypes from 'prop-types';
import React from 'react';

import { ConsentTitle } from '../lib/consentTitle';
import { DataProcessingConsent } from './dataProcessingConsent';
import { ConfigPropType, ConsentActionPropType } from '../lib/types';

export interface PolicyConsentDashboardProps {
    config: ConsentConfig
    subject: string
    
    /** Optional delegate principal */
    delegate?: string

    policyId: string | number

    optOut?: boolean

    elementIds?: string[] 
    language?: string

    type?: ConsentActionType

    title?: string | JSX.Element
    subtitle?: string | JSX.Element

    // Callbacks
    onAction?(consent: ConsentEvent): void
}

export interface PolicyConsentDashboardState {
    policy?: Policy, 
    policyUrl: string
}

const DEFAULT_POLICY_API = "https://api-server.production.signatu.com/api/v0"

const styles = (theme: Theme) => ({
    root: {
    }, 
    consentContainer: {
        marginTop: "1em", 
        marginBottom: "1em"
    }, 
})

class PolicyConsentDashboard extends React.Component<PolicyConsentDashboardProps & WithStyles, PolicyConsentDashboardState> {
    /** PropTypes for non-Typescript environments */
    static propTypes = {
        config: ConfigPropType,
        classes: PropTypes.any, 
        subject: PropTypes.string.isRequired, 
        delegate: PropTypes.string as PropTypes.Validator<string | undefined>, 

        policyId: PropTypes.string.isRequired, 
        elementIds: PropTypes.arrayOf(PropTypes.string.isRequired) as PropTypes.Validator<string[] | undefined>, 
        optOut: PropTypes.bool as PropTypes.Validator<boolean | undefined>,

        title: PropTypes.oneOfType([
            PropTypes.string, 
            PropTypes.element
        ]) as PropTypes.Validator<string | JSX.Element>,
        subtitle: PropTypes.oneOfType([
            PropTypes.string, 
            PropTypes.element
        ]) as PropTypes.Validator<string | JSX.Element>,
        type: ConsentActionPropType,
        language: PropTypes.string as PropTypes.Validator<string | undefined>,
        onAction: PropTypes.func as PropTypes.Validator<() => any | undefined>,
    }

    markdown = new Markdown()
    private policyEndPoint: string = ""

    constructor(props) {
        super(props)
        this.state = {policyUrl: ""}
    }
    
    async loadPolicy(props: PolicyConsentDashboardProps) {
        const base = props.config && props.config.policyAPI || DEFAULT_POLICY_API
        this.policyEndPoint = base.replace(/\/*$/, "") + "/policies"

        const policyUrl = `${this.policyEndPoint}/${props.policyId}`
        const policy = await Policy.loadPolicy(policyUrl)
        this.setState({policy, policyUrl})
    }

    componentWillMount() {
        this.loadPolicy(this.props)
    }

    async componentWillReceiveProps(props) {
        const {policyId, config} = props
        if (policyId !== this.props.policyId || this.props.config !== this.props.config) {
            this.loadPolicy(props)
        }
    }

    render() {
        const { config, subject, delegate, classes } = this.props
        const isoLang = this.props.language || 'en'
        const type = this.props.type || ConsentActionType.CHECKBOX

        const elementTypes = [
            'PolicyDataProcessing'
        ]
        const policyElements: PolicyDataProcessing[] = []
        const elementIds = this.props.elementIds
        if ( this.state.policy ) {
            this.state.policy.tree.traversePreorder((e: any) => {
                if (((!elementIds) || (elementIds.indexOf(e.elementId) > -1)) && 
                    elementTypes.indexOf(e.type) > -1) {
                    policyElements.push(e as PolicyDataProcessing)
                }
            })
        }

        return (
        <div className={classes.root} data-type="PolicyConsentDashboard">
            <ConsentTitle
                title={this.props.title}
                subtitle={<div>
                    Please read our <span><PolicyLink policyId={this.props.policyId as string}><span>Privacy Policy</span></PolicyLink>.</span>
                    &nbsp;
                    {this.props.subtitle}
                </div>}
            />
            {this.state.policy && policyElements.map(e => <div key={e.elementId} className={classes.consentContainer}>
                <DataProcessingConsent
                    /** Set all common props */
                    config={config}
                    subject={subject}
                    language={isoLang}

                    /** Overrides */
                    issuer={this.state.policyUrl}
                    scope={e.elementId}
                    target={`${this.state.policyUrl}`}
                    source={document.location && document.location.href || undefined}

                    delegate={delegate}

                    title={undefined}
                    subtitle={undefined}
                    
                    type={type}
                    dataprocessing={e}
                />
            </div>
            )}
        </div> 
        )
    }
}

const styled = withStyles<PolicyConsentDashboardProps>(styles)(PolicyConsentDashboard)
export { styled as PolicyConsentDashboard }
