import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Box, Divider, TextField, Typography, useTheme, } from '@material-ui/core';
import { OutlookLogoIcon } from '@fluentui/react-icons';
import { useTranslation } from 'react-i18next';
import { SideSheet } from '../../UI/surfaces/SideSheet';
import { AmbientAlert } from '../../UI/feedback/AmbientAlert';
import { AmbientCard } from '../../UI/surfaces/cards/AmbientCard';
import { FluentButton } from '../../UI/inputs/buttons/FluentButton';
import { getOutlookStatus, refreshOutlookStatus, subscribeOutlookStatus, } from './outlookIntegrationStatus';
import { disconnect, getAuthorizeUrl, getOutlookRedirectUri, sendMail, } from './outlookIntegrationClient';
export const OutlookIntegrationSideSheet = ({ open, onClose, closeOnConnect = false, appName, connectDescription, disclaimerText, footerNote, whyConnectTitle, whyConnectDescription, whyConnectItems, showTestEmail = false, testEmailDefaults, testEmailCopy, }) => {
    var _a;
    const { t } = useTranslation();
    const theme = useTheme();
    const resolvedAppName = appName || t('outlook.appName', 'this app');
    const [status, setStatus] = useState(() => getOutlookStatus());
    const [initializing, setInitializing] = useState(!status.loaded);
    const [action, setAction] = useState(null);
    const [feedback, setFeedback] = useState(null);
    const [testTo, setTestTo] = useState((_a = testEmailDefaults === null || testEmailDefaults === void 0 ? void 0 : testEmailDefaults.to) !== null && _a !== void 0 ? _a : '');
    const [testSubject, setTestSubject] = useState('');
    const [testBody, setTestBody] = useState('');
    useEffect(() => {
        const unsubscribe = subscribeOutlookStatus(setStatus);
        return () => unsubscribe();
    }, []);
    useEffect(() => {
        if (!open)
            return;
        setInitializing(true);
        refreshOutlookStatus()
            .catch(err => {
            setFeedback({
                severity: 'error',
                message: extractErrorMessage(err, t('outlook.errors.status', 'Unable to load Outlook status.')),
            });
        })
            .finally(() => setInitializing(false));
    }, [open, t]);
    useEffect(() => {
        if (!showTestEmail || !status.connected || !status.mailboxPrincipal) {
            return;
        }
        setTestTo(prev => (prev ? prev : status.mailboxPrincipal));
    }, [showTestEmail, status.connected, status.mailboxPrincipal]);
    useEffect(() => {
        const handler = event => {
            if (!event || !window || event.origin !== window.location.origin) {
                return;
            }
            const payload = typeof event.data === 'string'
                ? { type: event.data }
                : event.data || {};
            if (payload.type === 'outlookConnectSuccess') {
                refreshOutlookStatus().then(() => {
                    setFeedback({
                        severity: 'success',
                        message: t('outlook.connectSuccess', 'Outlook connected successfully.'),
                    });
                    if (closeOnConnect) {
                        onClose === null || onClose === void 0 ? void 0 : onClose();
                    }
                });
            }
            else if (payload.type === 'outlookConnectFailure') {
                setFeedback({
                    severity: 'error',
                    message: payload.message ||
                        t('outlook.connectFailed', 'Outlook connection failed. Please try again.'),
                });
            }
        };
        window.addEventListener('message', handler);
        return () => window.removeEventListener('message', handler);
    }, [closeOnConnect, onClose, t]);
    const openPopup = useCallback(url => {
        if (typeof window === 'undefined')
            return null;
        const width = 600;
        const height = 600;
        const left = (window.screen.width - width) / 2;
        const top = (window.screen.height - height) / 2;
        const features = `width=${width},height=${height},top=${top},left=${left},status=no,toolbar=no,menubar=no,location=no`;
        return window.open(url, 'OutlookConnectPopup', features);
    }, []);
    const handleConnect = useCallback(async () => {
        setAction('authorize');
        try {
            const redirectUri = getOutlookRedirectUri();
            const { authorizeUrl } = await getAuthorizeUrl({ redirectUri });
            const popup = openPopup(authorizeUrl);
            if (!popup) {
                throw new Error(t('outlook.errors.popupBlocked', 'Popup blocked. Please allow popups and try again.'));
            }
        }
        catch (err) {
            setFeedback({
                severity: 'error',
                message: extractErrorMessage(err, t('outlook.errors.connect', 'Unable to start the Outlook connection.')),
            });
        }
        finally {
            setAction(null);
        }
    }, [openPopup, t]);
    const handleDisconnect = useCallback(async () => {
        setAction('disconnect');
        try {
            await disconnect();
            await refreshOutlookStatus();
            setFeedback({
                severity: 'success',
                message: t('outlook.disconnectSuccess', 'Outlook disconnected.'),
            });
        }
        catch (err) {
            setFeedback({
                severity: 'error',
                message: extractErrorMessage(err, t('outlook.errors.disconnect', 'Unable to disconnect from Outlook.')),
            });
        }
        finally {
            setAction(null);
        }
    }, [t]);
    const handleSendTest = useCallback(async () => {
        const to = testTo.trim();
        if (!to) {
            setFeedback({
                severity: 'error',
                message: (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.missingRecipient) ||
                    t('outlook.errors.testTo', 'Please enter a recipient email.'),
            });
            return;
        }
        const fallbackSubject = (testEmailDefaults === null || testEmailDefaults === void 0 ? void 0 : testEmailDefaults.subject) ||
            t('outlook.sendTest.defaultSubject', `${resolvedAppName} test email`);
        const fallbackBody = (testEmailDefaults === null || testEmailDefaults === void 0 ? void 0 : testEmailDefaults.body) ||
            t('outlook.sendTest.defaultBody', `This is a test email sent from ${resolvedAppName} via Outlook.`);
        setAction('send-mail');
        try {
            await sendMail({
                to,
                subject: testSubject.trim() || fallbackSubject,
                body: testBody.trim() || fallbackBody,
            });
            setFeedback({
                severity: 'success',
                message: (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.success) ||
                    t('outlook.sendTest.success', 'Test email sent.'),
            });
        }
        catch (err) {
            setFeedback({
                severity: 'error',
                message: extractErrorMessage(err, (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.error) ||
                    t('outlook.errors.sendTest', 'Unable to send test email.')),
            });
        }
        finally {
            setAction(null);
        }
    }, [
        resolvedAppName,
        t,
        testBody,
        testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.error,
        testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.missingRecipient,
        testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.success,
        testEmailDefaults === null || testEmailDefaults === void 0 ? void 0 : testEmailDefaults.body,
        testEmailDefaults === null || testEmailDefaults === void 0 ? void 0 : testEmailDefaults.subject,
        testSubject,
        testTo,
    ]);
    const expiresLabel = useMemo(() => formatExpiresAt(status.expiresAt), [status.expiresAt]);
    const connectionDescription = useMemo(() => {
        if (status.connected && status.mailboxPrincipal) {
            return t('outlook.status.connectedAs', 'Connected as {{mailbox}}', {
                mailbox: status.mailboxPrincipal,
            });
        }
        if (status.connected) {
            return t('outlook.status.connectedNoMailbox', 'Outlook is connected.');
        }
        return (connectDescription ||
            t('outlook.connectDescription', 'Link your account to Outlook to manage your emails directly from our app.', { appName: resolvedAppName }));
    }, [connectDescription, resolvedAppName, status.connected, status.mailboxPrincipal, t]);
    const connectButtonLabel = useMemo(() => status.connected
        ? t('outlook.status.connected', 'Connected')
        : t('outlook.connectCta', 'Connect To Outlook'), [status.connected, t]);
    const connectButtonDisabled = useMemo(() => status.connected || action === 'authorize', [status.connected, action]);
    const disconnectDisabled = useMemo(() => action === 'disconnect', [action]);
    const sendTestDisabled = useMemo(() => !status.connected || action === 'send-mail', [status.connected, action]);
    const resolvedDisclaimer = disclaimerText ||
        t('outlook.sidesheetDisclaimer', `By signing in you are giving ${resolvedAppName} access to send emails on your behalf using your Outlook Mailbox.`, { appName: resolvedAppName });
    const resolvedWhyConnectTitle = whyConnectTitle ||
        t('outlook.whyConnect.title', 'Why connect to Outlook?');
    const resolvedWhyConnectDescription = whyConnectDescription ||
        t('outlook.whyConnect.description', `Certain actions within ${resolvedAppName} that require emailing will be enabled, such as:`, { appName: resolvedAppName });
    const resolvedFooterNote = footerNote ||
        t('outlook.todoNotes', `The ${resolvedAppName} backend securely stores your Mail.Send token and updates this status automatically.`, { appName: resolvedAppName });
    return (React.createElement(SideSheet, { title: t('outlook.title', 'Outlook Integration'), open: open, onClose: onClose, width: 560 }, React.createElement(AmbientAlert, { alertSeverity: "info", showAlert: true, alertMessage: resolvedDisclaimer }), feedback && (React.createElement(AmbientAlert, { alertSeverity: feedback.severity, showAlert: true, alertMessage: feedback.message, closeAlert: () => setFeedback(null) })), status.error && (React.createElement(AmbientAlert, { alertSeverity: "warning", showAlert: true, alertMessage: status.error })), React.createElement(Box, { display: "flex", flexDirection: "column", alignItems: "center", mt: 2, mb: 2, textAlign: "center" }, React.createElement(OutlookLogoIcon, { style: {
            fontSize: 128,
            width: 128,
            height: 128,
            color: theme.palette.info.dark,
        } }), React.createElement(Typography, { variant: "h6", gutterBottom: true }, status.connected
        ? t('outlook.status.header.connected', 'Connected to Outlook')
        : t('outlook.connectHeader', 'Connect to Outlook')), React.createElement(Typography, { variant: "body2", color: "textSecondary" }, connectionDescription), expiresLabel && (React.createElement(Typography, { variant: "caption", color: "textSecondary" }, t('outlook.status.expiresAt', 'Token expires {{date}}', {
        date: expiresLabel,
    })))), initializing && (React.createElement(Box, { mb: 2 }, React.createElement(Typography, { variant: "body2", color: "textSecondary" }, t('outlook.status.loading', 'Checking current Outlook connection...')))), React.createElement(Box, { mb: status.connected ? 2 : 4 }, React.createElement(FluentButton, { variant: "contained", color: "primary", fullWidth: true, onClick: handleConnect, disabled: connectButtonDisabled }, connectButtonLabel)), status.connected && (React.createElement(React.Fragment, null, React.createElement(FluentButton, { variant: "outlined", color: "primary", fullWidth: true, onClick: handleDisconnect, disabled: disconnectDisabled }, t('outlook.disconnect', 'Disconnect Outlook')), showTestEmail && (React.createElement(React.Fragment, null, React.createElement(Divider, { style: { margin: '24px 0' } }), React.createElement(Typography, { variant: "subtitle1", gutterBottom: true }, (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.title) ||
        t('outlook.sendTest.title', 'Send a Test Email')), React.createElement(Box, { display: "flex", flexDirection: "column", gridGap: 12, mb: 2 }, React.createElement(TextField, { label: (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.toLabel) || t('outlook.sendTest.to', 'To'), variant: "outlined", size: "small", fullWidth: true, value: testTo, onChange: event => setTestTo(event.target.value) }), React.createElement(TextField, { label: (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.subjectLabel) ||
            t('outlook.sendTest.subject', 'Subject'), variant: "outlined", size: "small", fullWidth: true, value: testSubject, onChange: event => setTestSubject(event.target.value) }), React.createElement(TextField, { label: (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.bodyLabel) ||
            t('outlook.sendTest.body', 'Body'), variant: "outlined", size: "small", multiline: true, minRows: 3, fullWidth: true, value: testBody, onChange: event => setTestBody(event.target.value) })), React.createElement(FluentButton, { variant: "contained", color: "primary", fullWidth: true, onClick: handleSendTest, disabled: sendTestDisabled }, action === 'send-mail'
        ? (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.sending) ||
            t('outlook.sendTest.sending', 'Sending...')
        : (testEmailCopy === null || testEmailCopy === void 0 ? void 0 : testEmailCopy.cta) ||
            t('outlook.sendTest.cta', 'Send Test Email')))), React.createElement(Divider, { style: { margin: '24px 0' } }))), React.createElement(AmbientCard, { title: resolvedWhyConnectTitle, fullWidth: true }, React.createElement(Box, { ml: 2 }, React.createElement(Typography, { variant: "body2" }, resolvedWhyConnectDescription), Array.isArray(whyConnectItems) && whyConnectItems.length > 0 && (React.createElement("ul", null, whyConnectItems.map((item, index) => (React.createElement("li", { key: `${index}-${String(item)}` }, React.createElement(Typography, { variant: "body2" }, item)))))))), React.createElement(Box, { mt: 3 }, React.createElement(Typography, { variant: "caption", color: "textSecondary" }, resolvedFooterNote))));
};
function formatExpiresAt(expiresAt) {
    if (!expiresAt)
        return null;
    const date = new Date(expiresAt);
    return Number.isNaN(date.getTime()) ? null : date.toLocaleString();
}
function extractErrorMessage(error, fallback) {
    var _a, _b;
    if (!error)
        return fallback;
    if (typeof error === 'string')
        return error;
    if (typeof error.message === 'string' && error.message.trim()) {
        return error.message;
    }
    const responseMessage = ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) || ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.statusText) || (error === null || error === void 0 ? void 0 : error.message);
    if (typeof responseMessage === 'string' && responseMessage.trim()) {
        return responseMessage;
    }
    return fallback;
}
export default OutlookIntegrationSideSheet;
//# sourceMappingURL=OutlookIntegrationSideSheet.js.map