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

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

export interface DataProcessingSpecProps {
    config: ConsentConfig
    subject: string
    issuer: string
    
    type: ConsentActionType
    delegate?: string

    specId: string 

    language?: string

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

export interface DataProcessingSpecState {
    spec?: PolicyDataProcessing
}

const DEFAULT_DATAPROCESSING_API: string = "https://api.signatu.com/dataprocessing/v0"

const styles = (theme: Theme) => ({
    root: {
        marginTop: theme.spacing.unit * 2
    }
})

class DataProcessingSpec extends React.Component<DataProcessingSpecProps & WithStyles, DataProcessingSpecState> {
    /** PropTypes for non-Typescript environments */
    static propTypes = {
        classes: PropTypes.any, 
        config: ConfigPropType,  
                
        subject: PropTypes.string.isRequired, 
        issuer: PropTypes.string.isRequired, 
        specId: PropTypes.string.isRequired, 

        delegate: PropTypes.string as PropTypes.Validator<string | undefined >, 

        type: ConsentActionPropType, 

        language: PropTypes.string as PropTypes.Validator<string | undefined >, 
        onAction: PropTypes.func as  PropTypes.Validator<(consent: ConsentEvent) => any | undefined >
    }

    state: DataProcessingSpecState = {}
    componentIsMounted = false

    private endPoint: string = ""

    async componentWillMount() {
        if (this.props.specId) {
            this.loadSpec(this.props.specId)
        }
    }
    componentDidMount() {
        this.componentIsMounted = true
    }
    componentWillUnmount() {
        this.componentIsMounted = false
    }

    async componentWillReceiveProps(newProps: DataProcessingSpecProps) {
        if (newProps.specId !== this.props.specId) {
            this.loadSpec(newProps.specId)
        }
    }

    async loadSpec(specId: string) {
        const base = this.props.config && this.props.config.dataprocessingAPI || DEFAULT_DATAPROCESSING_API
        this.endPoint = base.replace(/\/*$/, "") + `/dpspecs/${specId}`

        /** Fetch the data processing */
        const response = await fetch(this.endPoint, {
            method: 'GET', 
            headers: {
                Authorization: `Bearer ${this.props.config.accessToken}`
            }
        })
        const s = await response.json()
        if ( ! s ) {
            return
        }
        /** Make the specs PolicyDataProcessing objects */
        const spec = new PolicyDataProcessing(s.action, s.data, s.purpose, s.location, s.sensitive, s.consentTarget, s.legalBasis);
        (s.texts || []).forEach((t: any) => spec.addContent(
            new TextContent(t.value, new Language(t.language))
        ))

        if (this.componentIsMounted) {
            this.setState({spec})
        }
    }

    render() {
        const { config, classes, subject, issuer, type, delegate, language, children } = this.props
        const {spec} = this.state

        if (!spec) {
            return <div data-type="DataProcessingSpec">No spec: {this.props.specId}</div>
        }
        return (
        <div className={classes.root} data-type="DataProcessingSpec">  
            <DataProcessingConsent
                    /** Set all common props */
                    config={config}
                    subject={subject}
                    issuer={issuer}
                    delegate={delegate}
                    type={type}
                    language={language}

                    /** Overrides */
                    title={undefined}
                    subtitle={undefined}
                    
                    scope={spec.elementId}
                    target={this.endPoint}
                    source={document.location && document.location.href || undefined}
                    dataprocessing={spec} 
                    optOut={spec.legalBasis === LegalBasis.LEGITIMATE_INTEREST} 
            >

                {children}
            </DataProcessingConsent>
        </div>
        )
    }
}

const styled = withStyles<DataProcessingSpecProps>(styles)(DataProcessingSpec)
export { styled as DataProcessingSpec }
