import React from 'react';
import superagent from 'superagent';
import { Modal, Button, Form, Message, Icon } from 'semantic-ui-react';

/**
 * Step-up verification flow for OAuth client mutations.
 *
 * Opened automatically when the host component catches a 428
 * `step_up_required` response from a mutation. The flow:
 *
 *   1. User clicks "Send code". We POST to `/:id/step-up/challenge`
 *      which emails a 6-digit code to their Bigscreen account.
 *   2. User enters the code in a text field.
 *   3. User clicks "Verify". We POST to `/:id/step-up/verify`.
 *      On success, the modal closes and the host calls `onVerified()`
 *      which should retry whatever mutation originally failed with 428.
 *
 * Props:
 *   open       bool   whether the modal is visible
 *   clientUniqueId  string   /admin/oauth/clients/:uniqueId — the scope of the unlock
 *   clientName  string   for display
 *   onClose    ()     user dismissed without verifying
 *   onVerified ()     verification succeeded — host should retry its mutation
 */
export default class StepUpModal extends React.Component {
    constructor(props) {
        super(props);
        this.state = this.initialState();
    }

    initialState() {
        return {
            phase: 'request',      // 'request' | 'enter_code' | 'verifying' | 'sent_error'
            challengeId: null,
            code: '',
            error: null,
            sending: false
        };
    }

    componentDidUpdate(prevProps) {
        // Reset when the modal re-opens so a prior failure doesn't carry over.
        if (this.props.open && !prevProps.open) {
            this.setState(this.initialState());
        }
    }

    async onSendCode() {
        const { clientUniqueId } = this.props;
        this.setState({ sending: true, error: null });
        try {
            const res = await superagent
                .post(`/api/admin/oauth/clients/${clientUniqueId}/step-up/challenge`)
                .accept('json');
            this.setState({
                sending: false,
                phase: 'enter_code',
                challengeId: res.body.challengeId
            });
        } catch (e) {
            const body = e.response?.body || {};
            this.setState({
                sending: false,
                error: body.error_description || body.error || e.message,
                phase: body.error === 'locked' ? 'request' : this.state.phase
            });
        }
    }

    async onVerify() {
        const { clientUniqueId, onVerified } = this.props;
        const { challengeId, code } = this.state;
        if (!challengeId || !code) return;

        this.setState({ sending: true, error: null, phase: 'verifying' });
        try {
            await superagent
                .post(`/api/admin/oauth/clients/${clientUniqueId}/step-up/verify`)
                .accept('json')
                .send({ challengeId, code: code.trim() });
            this.setState({ sending: false });
            if (onVerified) onVerified();
        } catch (e) {
            const body = e.response?.body || {};
            const reason = body.error || e.message;
            // `mismatch` keeps them in the same phase to retry; `locked` /
            // `expired_or_unknown` force a restart from Send code.
            const backToRequest = reason === 'locked' || reason === 'expired_or_unknown';
            this.setState({
                sending: false,
                error: reasonToMessage(reason),
                phase: backToRequest ? 'request' : 'enter_code',
                challengeId: backToRequest ? null : challengeId,
                code: ''
            });
        }
    }

    renderRequestPhase() {
        return (
            <>
                <p>To modify <strong>{this.props.clientName}</strong>, we need to verify it's you.</p>
                <p style={{ color: '#666' }}>
                    We'll email a 6-digit code to the address on your Bigscreen account.
                    The code is valid for 10 minutes and unlocks mutations on this client only.
                </p>
            </>
        );
    }

    renderEnterCodePhase() {
        return (
            <>
                <Message info>
                    <Icon name="mail" />
                    A code was sent to your email. Enter it below within 10 minutes.
                </Message>
                <Form>
                    <Form.Input
                        label="6-digit code"
                        placeholder="000000"
                        value={this.state.code}
                        onChange={(e, d) => this.setState({ code: d.value.replace(/\D/g, '').slice(0, 6) })}
                        autoFocus
                        maxLength={6}
                    />
                </Form>
            </>
        );
    }

    render() {
        const { open, onClose, clientName } = this.props;
        const { phase, error, sending, code } = this.state;

        return (
            <Modal open={open} size="tiny" onClose={onClose}>
                <Modal.Header>
                    <Icon name="shield" /> Verify it's you
                </Modal.Header>
                <Modal.Content>
                    {error && <Message negative>{error}</Message>}
                    {phase === 'request' && this.renderRequestPhase()}
                    {(phase === 'enter_code' || phase === 'verifying') && this.renderEnterCodePhase()}
                </Modal.Content>
                <Modal.Actions>
                    <Button onClick={onClose} disabled={sending}>Cancel</Button>
                    {phase === 'request' && (
                        <Button primary loading={sending} onClick={() => this.onSendCode()}>
                            <Icon name="mail" /> Send code
                        </Button>
                    )}
                    {(phase === 'enter_code' || phase === 'verifying') && (
                        <Button
                            primary
                            loading={sending}
                            onClick={() => this.onVerify()}
                            disabled={code.length !== 6}
                        >
                            <Icon name="check" /> Verify & continue
                        </Button>
                    )}
                </Modal.Actions>
            </Modal>
        );
    }
}

function reasonToMessage(reason) {
    switch (reason) {
        case 'mismatch':
            return 'That code is incorrect. Try again.';
        case 'locked':
            return 'Too many failed attempts. Try again in 15 minutes.';
        case 'expired_or_unknown':
            return 'That code is expired or already used. Request a new one.';
        case 'scope_mismatch':
            return 'This code is for a different client. Request a new one.';
        default:
            return reason;
    }
}
