import * as React from 'react';
import {useContext, useState} from 'react';
import {
    Alert,
    CardActions,
    CardContent, Chip,
    FormControl,
    LinearProgress,
    Link,
    Portal,
    Select,
    Snackbar,
    Stack,
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableRow,
    useMediaQuery
} from "@mui/material";
import Tooltip from '@mui/material/Tooltip';
import Typography from "@mui/material/Typography";
import EditIcon from '@mui/icons-material/Edit';
import Container from "@mui/material/Container";
import Card from "@mui/material/Card";
import Button from "@mui/material/Button";
import {Trans, useTranslation} from "react-i18next";
import session from "../app/Session";
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import theme from "./theme";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import TextField from "@mui/material/TextField";
import routes from "./routes";
import IconButton from "@mui/material/IconButton";
import {formatBytes, formatShortDate, formatShortDateTime, openUrl} from "../app/utils";
import accountApi, {LimitBasis, Role, SubscriptionInterval, SubscriptionStatus} from "../app/AccountApi";
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import {Pref, PrefGroup} from "./Pref";
import db from "../app/db";
import i18n from "i18next";
import humanizeDuration from "humanize-duration";
import UpgradeDialog from "./UpgradeDialog";
import CelebrationIcon from "@mui/icons-material/Celebration";
import {AccountContext} from "./App";
import DialogFooter from "./DialogFooter";
import {Paragraph} from "./styles";
import CloseIcon from "@mui/icons-material/Close";
import {ContentCopy, Public} from "@mui/icons-material";
import MenuItem from "@mui/material/MenuItem";
import DialogContentText from "@mui/material/DialogContentText";
import {IncorrectPasswordError, UnauthorizedError} from "../app/errors";
import {ProChip} from "./SubscriptionPopup";
import AddIcon from "@mui/icons-material/Add";

const Account = () => {
    if (!session.exists()) {
        window.location.href = routes.app;
        return <></>;
    }
    return (
        <Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
            <Stack spacing={3}>
                <Basics/>
                <Stats/>
                <Tokens/>
                <Delete/>
            </Stack>
        </Container>
    );
};

const Basics = () => {
    const { t } = useTranslation();
    return (
        <Card sx={{p: 3}} aria-label={t("account_basics_title")}>
            <Typography variant="h5" sx={{marginBottom: 2}}>
                {t("account_basics_title")}
            </Typography>
            <PrefGroup>
                <Username/>
                <ChangePassword/>
                <PhoneNumbers/>
                <AccountType/>
            </PrefGroup>
        </Card>
    );
};

const Username = () => {
    const { t } = useTranslation();
    const { account } = useContext(AccountContext);
    const labelId = "prefUsername";

    return (
        <Pref labelId={labelId} title={t("account_basics_username_title")} description={t("account_basics_username_description")}>
            <div aria-labelledby={labelId}>
                {session.username()}
                {account?.role === Role.ADMIN
                    ? <>{" "}<Tooltip title={t("account_basics_username_admin_tooltip")}><span style={{cursor: "default"}}>👑</span></Tooltip></>
                    : ""}
            </div>
        </Pref>
    )
};

const ChangePassword = () => {
    const { t } = useTranslation();
    const [dialogKey, setDialogKey] = useState(0);
    const [dialogOpen, setDialogOpen] = useState(false);
    const labelId = "prefChangePassword";

    const handleDialogOpen = () => {
        setDialogKey(prev => prev+1);
        setDialogOpen(true);
    };

    const handleDialogClose = () => {
        setDialogOpen(false);
    };

    return (
        <Pref labelId={labelId} title={t("account_basics_password_title")} description={t("account_basics_password_description")}>
            <div aria-labelledby={labelId}>
                <Typography color="gray" sx={{float: "left", fontSize: "0.7rem", lineHeight: "3.5"}}>⬤⬤⬤⬤⬤⬤⬤⬤⬤⬤</Typography>
                <IconButton onClick={handleDialogOpen} aria-label={t("account_basics_password_description")}>
                    <EditIcon/>
                </IconButton>
            </div>
            <ChangePasswordDialog
                key={`changePasswordDialog${dialogKey}`}
                open={dialogOpen}
                onClose={handleDialogClose}
            />
        </Pref>
    )
};

const ChangePasswordDialog = (props) => {
    const { t } = useTranslation();
    const [error, setError] = useState("");
    const [currentPassword, setCurrentPassword] = useState("");
    const [newPassword, setNewPassword] = useState("");
    const [confirmPassword, setConfirmPassword] = useState("");
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));

    const handleDialogSubmit = async () => {
        try {
            console.debug(`[Account] Changing password`);
            await accountApi.changePassword(currentPassword, newPassword);
            props.onClose();
        } catch (e) {
            console.log(`[Account] Error changing password`, e);
            if (e instanceof IncorrectPasswordError) {
                setError(t("account_basics_password_dialog_current_password_incorrect"));
            } else if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setError(e.message);
            }
        }
    };

    return (
        <Dialog open={props.open} onClose={props.onCancel} fullScreen={fullScreen}>
            <DialogTitle>{t("account_basics_password_dialog_title")}</DialogTitle>
            <DialogContent>
                <TextField
                    margin="dense"
                    id="current-password"
                    label={t("account_basics_password_dialog_current_password_label")}
                    aria-label={t("account_basics_password_dialog_current_password_label")}
                    type="password"
                    value={currentPassword}
                    onChange={ev => setCurrentPassword(ev.target.value)}
                    fullWidth
                    variant="standard"
                />
                <TextField
                    margin="dense"
                    id="new-password"
                    label={t("account_basics_password_dialog_new_password_label")}
                    aria-label={t("account_basics_password_dialog_new_password_label")}
                    type="password"
                    value={newPassword}
                    onChange={ev => setNewPassword(ev.target.value)}
                    fullWidth
                    variant="standard"
                />
                <TextField
                    margin="dense"
                    id="confirm"
                    label={t("account_basics_password_dialog_confirm_password_label")}
                    aria-label={t("account_basics_password_dialog_confirm_password_label")}
                    type="password"
                    value={confirmPassword}
                    onChange={ev => setConfirmPassword(ev.target.value)}
                    fullWidth
                    variant="standard"
                />
            </DialogContent>
            <DialogFooter status={error}>
                <Button onClick={props.onClose}>{t("common_cancel")}</Button>
                <Button
                    onClick={handleDialogSubmit}
                    disabled={newPassword.length === 0 || currentPassword.length === 0 || newPassword !== confirmPassword}
                >
                    {t("account_basics_password_dialog_button_submit")}
                </Button>
            </DialogFooter>
        </Dialog>
    );
};

const AccountType = () => {
    const { t } = useTranslation();
    const { account } = useContext(AccountContext);
    const [upgradeDialogKey, setUpgradeDialogKey] = useState(0);
    const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false);
    const [showPortalError, setShowPortalError] = useState(false);

    if (!account) {
        return <></>;
    }

    const handleUpgradeClick = () => {
        setUpgradeDialogKey(k => k + 1);
        setUpgradeDialogOpen(true);
    }

    const handleManageBilling = async () => {
        try {
            const response = await accountApi.createBillingPortalSession();
            window.open(response.redirect_url, "billing_portal");
        } catch (e) {
            console.log(`[Account] Error opening billing portal`, e);
            if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setShowPortalError(true);
            }
        }
    };

    let accountType;
    if (account.role === Role.ADMIN) {
        const tierSuffix = (account.tier) ? t("account_basics_tier_admin_suffix_with_tier", { tier: account.tier.name }) : t("account_basics_tier_admin_suffix_no_tier");
        accountType = `${t("account_basics_tier_admin")} ${tierSuffix}`;
    } else if (!account.tier) {
        accountType = (config.enable_payments) ? t("account_basics_tier_free") : t("account_basics_tier_basic");
    } else {
        accountType = account.tier.name;
        if (account.billing?.interval === SubscriptionInterval.MONTH) {
            accountType += ` (${t("account_basics_tier_interval_monthly")})`;
        } else if (account.billing?.interval === SubscriptionInterval.YEAR) {
            accountType += ` (${t("account_basics_tier_interval_yearly")})`;
        }
    }

    return (
        <Pref
            alignTop={account.billing?.status === SubscriptionStatus.PAST_DUE || account.billing?.cancel_at > 0}
            title={t("account_basics_tier_title")}
            description={t("account_basics_tier_description")}
        >
            <div>
                {accountType}
                {account.billing?.paid_until && !account.billing?.cancel_at &&
                    <Tooltip title={t("account_basics_tier_paid_until", { date: formatShortDate(account.billing?.paid_until) })}>
                        <span><InfoIcon/></span>
                    </Tooltip>
                }
                {config.enable_payments && account.role === Role.USER && !account.billing?.subscription &&
                    <Button
                        variant="outlined"
                        size="small"
                        startIcon={<CelebrationIcon sx={{ color: "#55b86e" }}/>}
                        onClick={handleUpgradeClick}
                        sx={{ml: 1}}
                    >{t("account_basics_tier_upgrade_button")}</Button>
                }
                {config.enable_payments && account.role === Role.USER && account.billing?.subscription &&
                    <Button
                        variant="outlined"
                        size="small"
                        onClick={handleUpgradeClick}
                        sx={{ml: 1}}
                    >{t("account_basics_tier_change_button")}</Button>
                }
                {config.enable_payments && account.role === Role.USER && account.billing?.customer &&
                    <Button
                        variant="outlined"
                        size="small"
                        onClick={handleManageBilling}
                        sx={{ml: 1}}
                    >{t("account_basics_tier_manage_billing_button")}</Button>
                }
                {config.enable_payments &&
                    <UpgradeDialog
                        key={`upgradeDialogFromAccount${upgradeDialogKey}`}
                        open={upgradeDialogOpen}
                        onCancel={() => setUpgradeDialogOpen(false)}
                    />
                }
            </div>
            {account.billing?.status === SubscriptionStatus.PAST_DUE &&
                <Alert severity="error" sx={{mt: 1}}>{t("account_basics_tier_payment_overdue")}</Alert>
            }
            {account.billing?.cancel_at > 0 &&
                <Alert severity="warning" sx={{mt: 1}}>{t("account_basics_tier_canceled_subscription", { date: formatShortDate(account.billing.cancel_at) })}</Alert>
            }
            <Portal>
                <Snackbar
                    open={showPortalError}
                    autoHideDuration={3000}
                    onClose={() => setShowPortalError(false)}
                    message={t("account_usage_cannot_create_portal_session")}
                />
            </Portal>
        </Pref>
    )
};

const PhoneNumbers = () => {
    const { t } = useTranslation();
    const { account } = useContext(AccountContext);
    const [dialogKey, setDialogKey] = useState(0);
    const [dialogOpen, setDialogOpen] = useState(false);
    const [snackOpen, setSnackOpen] = useState(false);
    const labelId = "prefPhoneNumbers";

    const handleDialogOpen = () => {
        setDialogKey(prev => prev+1);
        setDialogOpen(true);
    };

    const handleDialogClose = () => {
        setDialogOpen(false);
    };

    const handleCopy = (phoneNumber) => {
        navigator.clipboard.writeText(phoneNumber);
        setSnackOpen(true);
    };

    const handleDelete = async (phoneNumber) => {
        try {
            await accountApi.deletePhoneNumber(phoneNumber);
        } catch (e) {
            console.log(`[Account] Error deleting phone number`, e);
            if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            }
        }
    };

    if (!config.enable_calls) {
        return null;
    }

    return (
        <Pref labelId={labelId} title={t("account_basics_phone_numbers_title")} description={t("account_basics_phone_numbers_description")}>
            <div aria-labelledby={labelId}>
                {account?.phone_numbers?.map(phoneNumber =>
                        <Chip
                            label={
                                <Tooltip title={t("common_copy_to_clipboard")}>
                                   <span>{phoneNumber}</span>
                                </Tooltip>
                            }
                            variant="outlined"
                            onClick={() => handleCopy(phoneNumber)}
                            onDelete={() => handleDelete(phoneNumber)}
                        />
                )}
                {!account?.phone_numbers &&
                    <em>{t("account_basics_phone_numbers_no_phone_numbers_yet")}</em>
                }
                <IconButton onClick={handleDialogOpen}><AddIcon/></IconButton>
            </div>
            <AddPhoneNumberDialog
                key={`addPhoneNumberDialog${dialogKey}`}
                open={dialogOpen}
                onClose={handleDialogClose}
            />
            <Portal>
                <Snackbar
                    open={snackOpen}
                    autoHideDuration={3000}
                    onClose={() => setSnackOpen(false)}
                    message={t("account_basics_phone_numbers_copied_to_clipboard")}
                />
            </Portal>
        </Pref>
    )
};

const AddPhoneNumberDialog = (props) => {
    const { t } = useTranslation();
    const [error, setError] = useState("");
    const [phoneNumber, setPhoneNumber] = useState("");
    const [code, setCode] = useState("");
    const [sending, setSending] = useState(false);
    const [verificationCodeSent, setVerificationCodeSent] = useState(false);
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));

    const handleDialogSubmit = async () => {
        if (!verificationCodeSent) {
            await verifyPhone();
        } else {
            await checkVerifyPhone();
        }
    };

    const handleCancel = () => {
        if (verificationCodeSent) {
            setVerificationCodeSent(false);
        } else {
            props.onClose();
        }
    };

    const verifyPhone = async () => {
        try {
            setSending(true);
            await accountApi.verifyPhone(phoneNumber);
            setVerificationCodeSent(true);
        } catch (e) {
            console.log(`[Account] Error sending verification`, e);
            if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setError(e.message);
            }
        } finally {
            setSending(false);
        }
    };

    const checkVerifyPhone = async () => {
        try {
            setSending(true);
            await accountApi.checkVerifyPhone(phoneNumber, code);
            props.onClose();
        } catch (e) {
            console.log(`[Account] Error confirming verification`, e);
            if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setError(e.message);
            }
        } finally {
            setSending(false);
        }
    };

    return (
        <Dialog open={props.open} onClose={props.onCancel} fullScreen={fullScreen}>
            <DialogTitle>{t("account_basics_phone_numbers_dialog_title")}</DialogTitle>
            <DialogContent>
                <DialogContentText>
                    {t("account_basics_phone_numbers_dialog_description")}
                </DialogContentText>
                {!verificationCodeSent &&
                    <TextField
                        margin="dense"
                        label={t("account_basics_phone_numbers_dialog_number_label")}
                        aria-label={t("account_basics_phone_numbers_dialog_number_label")}
                        placeholder={t("account_basics_phone_numbers_dialog_number_placeholder")}
                        type="tel"
                        value={phoneNumber}
                        onChange={ev => setPhoneNumber(ev.target.value)}
                        fullWidth
                        inputProps={{ inputMode: 'tel', pattern: '\+[0-9]*' }}
                        variant="standard"
                    />
                }
                {verificationCodeSent &&
                    <TextField
                        margin="dense"
                        label={t("account_basics_phone_numbers_dialog_code_label")}
                        aria-label={t("account_basics_phone_numbers_dialog_code_label")}
                        placeholder={t("account_basics_phone_numbers_dialog_code_placeholder")}
                        type="text"
                        value={code}
                        onChange={ev => setCode(ev.target.value)}
                        fullWidth
                        inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }}
                        variant="standard"
                    />
                }
            </DialogContent>
            <DialogFooter status={error}>
                <Button onClick={handleCancel}>{verificationCodeSent ? t("common_back") : t("common_cancel")}</Button>
                <Button onClick={handleDialogSubmit} disabled={sending || !/^\+\d+$/.test(phoneNumber)}>
                    {verificationCodeSent ?t("account_basics_phone_numbers_dialog_check_verification_button")  : t("account_basics_phone_numbers_dialog_send_verification_button")}
                </Button>
            </DialogFooter>
        </Dialog>
    );
};


const Stats = () => {
    const { t } = useTranslation();
    const { account } = useContext(AccountContext);

    if (!account) {
        return <></>;
    }

    const normalize = (value, max) => {
        return Math.min(value / max * 100, 100);
    };

    return (
        <Card sx={{p: 3}} aria-label={t("account_usage_title")}>
            <Typography variant="h5" sx={{marginBottom: 2}}>
                {t("account_usage_title")}
            </Typography>
            <PrefGroup>
                {(account.role === Role.ADMIN || account.limits.reservations > 0) &&
                    <Pref title={t("account_usage_reservations_title")}>
                        <div>
                            <Typography variant="body2" sx={{float: "left"}}>{account.stats.reservations.toLocaleString()}</Typography>
                            <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.reservations.toLocaleString() }) : t("account_usage_unlimited")}</Typography>
                        </div>
                        <LinearProgress
                            variant="determinate"
                            value={account.role === Role.USER && account.limits.reservations > 0 ? normalize(account.stats.reservations, account.limits.reservations) : 100}
                        />
                    </Pref>
                }
                <Pref title={
                    <>
                        {t("account_usage_messages_title")}
                        <Tooltip title={t("account_usage_limits_reset_daily")}><span><InfoIcon/></span></Tooltip>
                    </>
                }>
                    <div>
                        <Typography variant="body2" sx={{float: "left"}}>{account.stats.messages.toLocaleString()}</Typography>
                        <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.messages.toLocaleString() }) : t("account_usage_unlimited")}</Typography>
                    </div>
                    <LinearProgress
                        variant="determinate"
                        value={account.role === Role.USER ? normalize(account.stats.messages, account.limits.messages) : 100}
                    />
                </Pref>
                <Pref title={
                    <>
                        {t("account_usage_emails_title")}
                        <Tooltip title={t("account_usage_limits_reset_daily")}><span><InfoIcon/></span></Tooltip>
                    </>
                }>
                    <div>
                        <Typography variant="body2" sx={{float: "left"}}>{account.stats.emails.toLocaleString()}</Typography>
                        <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.emails.toLocaleString() }) : t("account_usage_unlimited")}</Typography>
                    </div>
                    <LinearProgress
                        variant="determinate"
                        value={account.role === Role.USER ? normalize(account.stats.emails, account.limits.emails) : 100}
                    />
                </Pref>
                {(account.role === Role.ADMIN || account.limits.calls > 0) &&
                    <Pref title={
                        <>
                            {t("account_usage_calls_title")}
                            <Tooltip title={t("account_usage_limits_reset_daily")}><span><InfoIcon/></span></Tooltip>
                        </>
                    }>
                        <div>
                            <Typography variant="body2" sx={{float: "left"}}>{account.stats.calls.toLocaleString()}</Typography>
                            <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.calls.toLocaleString() }) : t("account_usage_unlimited")}</Typography>
                        </div>
                        <LinearProgress
                            variant="determinate"
                            value={account.role === Role.USER && account.limits.calls > 0 ? normalize(account.stats.calls, account.limits.calls) : 100}
                        />
                    </Pref>
                }
                <Pref
                    alignTop
                    title={t("account_usage_attachment_storage_title")}
                    description={t("account_usage_attachment_storage_description", {
                        filesize: formatBytes(account.limits.attachment_file_size),
                        expiry: humanizeDuration(account.limits.attachment_expiry_duration * 1000, {
                            language: i18n.resolvedLanguage,
                            fallbacks: ["en"]
                        })
                    })}
                >
                    <div>
                        <Typography variant="body2" sx={{float: "left"}}>{formatBytes(account.stats.attachment_total_size)}</Typography>
                        <Typography variant="body2" sx={{float: "right"}}>{account.role === Role.USER ? t("account_usage_of_limit", { limit: formatBytes(account.limits.attachment_total_size) }) : t("account_usage_unlimited")}</Typography>
                    </div>
                    <LinearProgress
                        variant="determinate"
                        value={account.role === Role.USER ? normalize(account.stats.attachment_total_size, account.limits.attachment_total_size) : 100}
                    />
                </Pref>
                {config.enable_reservations && account.role === Role.USER && account.limits.reservations === 0 &&
                    <Pref title={<>{t("account_usage_reservations_title")}{config.enable_payments && <ProChip/>}</>}>
                        <em>{t("account_usage_reservations_none")}</em>
                    </Pref>
                }
                {config.enable_calls && account.role === Role.USER && account.limits.calls === 0 &&
                    <Pref title={<>{t("account_usage_calls_title")}{config.enable_payments && <ProChip/>}</>}>
                        <em>{t("account_usage_calls_none")}</em>
                    </Pref>
                }
            </PrefGroup>
            {account.role === Role.USER && account.limits.basis === LimitBasis.IP &&
                <Typography variant="body1">
                    {t("account_usage_basis_ip_description")}
                </Typography>
            }
        </Card>
    );
};

const InfoIcon = () => {
    return (
        <InfoOutlinedIcon sx={{
            verticalAlign: "middle",
            width: "18px",
            marginLeft: "4px",
            color: "gray"
        }}/>
    );
}


const Tokens = () => {
    const { t } = useTranslation();
    const { account } = useContext(AccountContext);
    const [dialogKey, setDialogKey] = useState(0);
    const [dialogOpen, setDialogOpen] = useState(false);
    const tokens = account?.tokens || [];

    const handleCreateClick = () => {
        setDialogKey(prev => prev+1);
        setDialogOpen(true);
    };

    const handleDialogClose = () => {
        setDialogOpen(false);
    };

    const handleDialogSubmit = async (user) => {
        setDialogOpen(false);
        //
    };
    return (
        <Card sx={{ padding: 1 }} aria-label={t("prefs_users_title")}>
            <CardContent sx={{ paddingBottom: 1 }}>
                <Typography variant="h5" sx={{marginBottom: 2}}>
                    {t("account_tokens_title")}
                </Typography>
                <Paragraph>
                    <Trans
                        i18nKey="account_tokens_description"
                        components={{
                            Link: <Link href="/docs/publish/#access-tokens"/>
                        }}
                    />
                </Paragraph>
                {tokens?.length > 0 && <TokensTable tokens={tokens}/>}
            </CardContent>
            <CardActions>
                <Button onClick={handleCreateClick}>{t("account_tokens_table_create_token_button")}</Button>
            </CardActions>
            <TokenDialog
                key={`tokenDialogCreate${dialogKey}`}
                open={dialogOpen}
                onClose={handleDialogClose}
            />
        </Card>
    );
};

const TokensTable = (props) => {
    const { t } = useTranslation();
    const [snackOpen, setSnackOpen] = useState(false);
    const [upsertDialogKey, setUpsertDialogKey] = useState(0);
    const [upsertDialogOpen, setUpsertDialogOpen] = useState(false);
    const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
    const [selectedToken, setSelectedToken] = useState(null);

    const tokens = (props.tokens || [])
        .sort( (a, b) => {
            if (a.token === session.token()) {
                return -1;
            } else if (b.token === session.token()) {
                return 1;
            }
            return a.token.localeCompare(b.token);
        });

    const handleEditClick = (token) => {
        setUpsertDialogKey(prev => prev+1);
        setSelectedToken(token);
        setUpsertDialogOpen(true);
    };

    const handleDialogClose = () => {
        setUpsertDialogOpen(false);
        setDeleteDialogOpen(false);
        setSelectedToken(null);
    };

    const handleDeleteClick = async (token) => {
        setSelectedToken(token);
        setDeleteDialogOpen(true);
    };

    const handleCopy = async (token) => {
        await navigator.clipboard.writeText(token);
        setSnackOpen(true);
    };

    return (
        <Table size="small" aria-label={t("account_tokens_title")}>
            <TableHead>
                <TableRow>
                    <TableCell sx={{paddingLeft: 0}}>{t("account_tokens_table_token_header")}</TableCell>
                    <TableCell>{t("account_tokens_table_label_header")}</TableCell>
                    <TableCell>{t("account_tokens_table_expires_header")}</TableCell>
                    <TableCell>{t("account_tokens_table_last_access_header")}</TableCell>
                    <TableCell/>
                </TableRow>
            </TableHead>
            <TableBody>
                {tokens.map(token => (
                    <TableRow
                        key={token.token}
                        sx={{'&:last-child td, &:last-child th': { border: 0 }}}
                    >
                        <TableCell component="th" scope="row" sx={{ paddingLeft: 0, whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_token_header")}>
                            <span>
                                <span style={{fontFamily: "Monospace", fontSize: "0.9rem"}}>{token.token.slice(0, 12)}</span>
                                ...
                                <Tooltip title={t("common_copy_to_clipboard")} placement="right">
                                    <IconButton onClick={() => handleCopy(token.token)}><ContentCopy/></IconButton>
                                </Tooltip>
                            </span>
                        </TableCell>
                        <TableCell aria-label={t("account_tokens_table_label_header")}>
                            {token.token === session.token() && <em>{t("account_tokens_table_current_session")}</em>}
                            {token.token !== session.token() && (token.label || "-")}
                        </TableCell>
                        <TableCell sx={{ whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_expires_header")}>
                            {token.expires ? formatShortDateTime(token.expires) : <em>{t("account_tokens_table_never_expires")}</em>}
                        </TableCell>
                        <TableCell sx={{ whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_last_access_header")}>
                            <div style={{ display: "flex", alignItems: "center" }}>
                                <span>{formatShortDateTime(token.last_access)}</span>
                                <Tooltip title={t("account_tokens_table_last_origin_tooltip", { ip: token.last_origin })}>
                                    <IconButton onClick={() => openUrl(`https://whatismyipaddress.com/ip/${token.last_origin}`)}>
                                        <Public />
                                    </IconButton>
                                </Tooltip>
                            </div>
                        </TableCell>
                        <TableCell align="right" sx={{ whiteSpace: "nowrap" }}>
                            {token.token !== session.token() &&
                                <>
                                    <IconButton onClick={() => handleEditClick(token)} aria-label={t("account_tokens_dialog_title_edit")}>
                                        <EditIcon/>
                                    </IconButton>
                                    <IconButton onClick={() => handleDeleteClick(token)} aria-label={t("account_tokens_dialog_title_delete")}>
                                        <CloseIcon/>
                                    </IconButton>
                                </>
                            }
                            {token.token === session.token() &&
                                <Tooltip title={t("account_tokens_table_cannot_delete_or_edit")}>
                                    <span>
                                        <IconButton disabled><EditIcon/></IconButton>
                                        <IconButton disabled><CloseIcon/></IconButton>
                                    </span>
                                </Tooltip>
                            }
                        </TableCell>
                    </TableRow>
                ))}
            </TableBody>
            <Portal>
                <Snackbar
                    open={snackOpen}
                    autoHideDuration={3000}
                    onClose={() => setSnackOpen(false)}
                    message={t("account_tokens_table_copied_to_clipboard")}
                />
            </Portal>
            <TokenDialog
                key={`tokenDialogEdit${upsertDialogKey}`}
                open={upsertDialogOpen}
                token={selectedToken}
                onClose={handleDialogClose}
            />
            <TokenDeleteDialog
                open={deleteDialogOpen}
                token={selectedToken}
                onClose={handleDialogClose}
            />
        </Table>
    );
};

const TokenDialog = (props) => {
    const { t } = useTranslation();
    const [error, setError] = useState("");
    const [label, setLabel] = useState(props.token?.label || "");
    const [expires, setExpires] = useState(props.token ? -1 : 0);
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
    const editMode = !!props.token;

    const handleSubmit = async () => {
        try {
            if (editMode) {
                await accountApi.updateToken(props.token.token, label, expires);
            } else {
                await accountApi.createToken(label, expires);
            }
            props.onClose();
        } catch (e) {
            console.log(`[Account] Error creating token`, e);
            if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setError(e.message);
            }
        }
    };

    return (
        <Dialog open={props.open} onClose={props.onClose} maxWidth="sm" fullWidth fullScreen={fullScreen}>
            <DialogTitle>{editMode ? t("account_tokens_dialog_title_edit") : t("account_tokens_dialog_title_create")}</DialogTitle>
            <DialogContent>
                <TextField
                    margin="dense"
                    id="token-label"
                    label={t("account_tokens_dialog_label")}
                    aria-label={t("account_delete_dialog_label")}
                    type="text"
                    value={label}
                    onChange={ev => setLabel(ev.target.value)}
                    fullWidth
                    variant="standard"
                />
                <FormControl fullWidth variant="standard" sx={{ mt: 1 }}>
                    <Select value={expires} onChange={(ev) => setExpires(ev.target.value)} aria-label={t("account_tokens_dialog_expires_label")}>
                        {editMode && <MenuItem value={-1}>{t("account_tokens_dialog_expires_unchanged")}</MenuItem>}
                        <MenuItem value={0}>{t("account_tokens_dialog_expires_never")}</MenuItem>
                        <MenuItem value={21600}>{t("account_tokens_dialog_expires_x_hours", { hours: 6 })}</MenuItem>
                        <MenuItem value={43200}>{t("account_tokens_dialog_expires_x_hours", { hours: 12 })}</MenuItem>
                        <MenuItem value={259200}>{t("account_tokens_dialog_expires_x_days", { days: 3 })}</MenuItem>
                        <MenuItem value={604800}>{t("account_tokens_dialog_expires_x_days", { days: 7 })}</MenuItem>
                        <MenuItem value={2592000}>{t("account_tokens_dialog_expires_x_days", { days: 30 })}</MenuItem>
                        <MenuItem value={7776000}>{t("account_tokens_dialog_expires_x_days", { days: 90 })}</MenuItem>
                        <MenuItem value={15552000}>{t("account_tokens_dialog_expires_x_days", { days: 180 })}</MenuItem>
                    </Select>
                </FormControl>
            </DialogContent>
            <DialogFooter status={error}>
                <Button onClick={props.onClose}>{t("account_tokens_dialog_button_cancel")}</Button>
                <Button onClick={handleSubmit}>{editMode ? t("account_tokens_dialog_button_update") : t("account_tokens_dialog_button_create")}</Button>
            </DialogFooter>
        </Dialog>
    );
};

const TokenDeleteDialog = (props) => {
    const { t } = useTranslation();
    const [error, setError] = useState("");

    const handleSubmit = async () => {
        try {
            await accountApi.deleteToken(props.token.token);
            props.onClose();
        } catch (e) {
            console.log(`[Account] Error deleting token`, e);
            if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setError(e.message);
            }
        }
    };

    return (
        <Dialog open={props.open} onClose={props.onClose}>
            <DialogTitle>{t("account_tokens_delete_dialog_title")}</DialogTitle>
            <DialogContent>
                <DialogContentText>
                    <Trans i18nKey="account_tokens_delete_dialog_description"/>
                </DialogContentText>
            </DialogContent>
            <DialogFooter status>
                <Button onClick={props.onClose}>{t("common_cancel")}</Button>
                <Button onClick={handleSubmit} color="error">{t("account_tokens_delete_dialog_submit_button")}</Button>
            </DialogFooter>
        </Dialog>
    );
}


const Delete = () => {
    const { t } = useTranslation();
    return (
        <Card sx={{p: 3}} aria-label={t("account_delete_title")}>
            <Typography variant="h5" sx={{marginBottom: 2}}>
                {t("account_delete_title")}
            </Typography>
            <PrefGroup>
                <DeleteAccount/>
            </PrefGroup>
        </Card>
    );
};

const DeleteAccount = () => {
    const { t } = useTranslation();
    const [dialogKey, setDialogKey] = useState(0);
    const [dialogOpen, setDialogOpen] = useState(false);

    const handleDialogOpen = () => {
        setDialogKey(prev => prev+1);
        setDialogOpen(true);
    };

    const handleDialogClose = () => {
        setDialogOpen(false);
    };

    return (
        <Pref title={t("account_delete_title")} description={t("account_delete_description")}>
            <div>
                <Button fullWidth={false} variant="outlined" color="error" startIcon={<DeleteOutlineIcon />} onClick={handleDialogOpen}>
                    {t("account_delete_title")}
                </Button>
            </div>
            <DeleteAccountDialog
                key={`deleteAccountDialog${dialogKey}`}
                open={dialogOpen}
                onClose={handleDialogClose}
            />
        </Pref>
    )
};

const DeleteAccountDialog = (props) => {
    const { t } = useTranslation();
    const { account } = useContext(AccountContext);
    const [error, setError] = useState("");
    const [password, setPassword] = useState("");
    const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));

    const handleSubmit = async () => {
        try {
            await accountApi.delete(password);
            await db.delete();
            console.debug(`[Account] Account deleted`);
            session.resetAndRedirect(routes.app);
        } catch (e) {
            console.log(`[Account] Error deleting account`, e);
            if (e instanceof IncorrectPasswordError) {
                setError(t("account_basics_password_dialog_current_password_incorrect"));
            } else if (e instanceof UnauthorizedError) {
                session.resetAndRedirect(routes.login);
            } else {
                setError(e.message);
            }
        }
    };

    return (
        <Dialog open={props.open} onClose={props.onClose} fullScreen={fullScreen}>
            <DialogTitle>{t("account_delete_title")}</DialogTitle>
            <DialogContent>
                <Typography variant="body1">
                    {t("account_delete_dialog_description")}
                </Typography>
                <TextField
                    margin="dense"
                    id="account-delete-confirm"
                    label={t("account_delete_dialog_label")}
                    aria-label={t("account_delete_dialog_label")}
                    type="password"
                    value={password}
                    onChange={ev => setPassword(ev.target.value)}
                    fullWidth
                    variant="standard"
                />
                {account?.billing?.subscription &&
                    <Alert severity="warning" sx={{mt: 1}}>{t("account_delete_dialog_billing_warning")}</Alert>
                }
            </DialogContent>
            <DialogFooter status={error}>
                <Button onClick={props.onClose}>{t("account_delete_dialog_button_cancel")}</Button>
                <Button onClick={handleSubmit} color="error" disabled={password.length === 0}>{t("account_delete_dialog_button_submit")}</Button>
            </DialogFooter>
        </Dialog>
    );
};

export default Account;