import {
    ActionIcon,
    Button,
    FileInput,
    Group,
    Modal,
    Stack,
    Text,
    Tooltip,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { IconFileDollar, IconUpload } from '@tabler/icons-react';
import axios from 'axios';
import { useMemo, useState } from 'react';

type InvoicePdfButtonProps = {
    invoiceId: number;
    invoiceNo?: string | null;
    display?: 'icon' | 'button';
    label?: string;
};

type InvoicePdfUploadResponse = {
    message?: string;
    pdf_url?: string;
};

export default function InvoicePdfButton({
    invoiceId,
    invoiceNo,
    display = 'icon',
    label = 'View Invoice',
}: InvoicePdfButtonProps) {
    const [opened, setOpened] = useState(false);
    const [file, setFile] = useState<File | null>(null);
    const [checking, setChecking] = useState(false);
    const [uploading, setUploading] = useState(false);
    const [error, setError] = useState<string | null>(null);

    const urls = useMemo(
        () => ({
            view: route('client-invoices.getPdfInvoice', { id: invoiceId }),
            upload: route('client-invoices.pdf.upload', {
                invoice: invoiceId,
            }),
        }),
        [invoiceId],
    );

    const openInvoice = (url = urls.view) => {
        window.open(url, '_blank', 'noopener,noreferrer');
    };

    const handleView = async () => {
        setChecking(true);
        setError(null);

        try {
            const response = await axios.get<Blob>(urls.view, {
                responseType: 'blob',
                validateStatus: (status) =>
                    (status >= 200 && status < 300) || status === 404,
            });

            if (response.status === 404) {
                setOpened(true);
                return;
            }

            const blobUrl = URL.createObjectURL(response.data);
            openInvoice(blobUrl);
            window.setTimeout(() => URL.revokeObjectURL(blobUrl), 60_000);
        } catch {
            notifications.show({
                title: 'Unable to open invoice',
                message: 'Please try again later.',
                color: 'red',
            });
        } finally {
            setChecking(false);
        }
    };

    const handleUpload = async () => {
        if (!file) {
            setError('Select a PDF invoice to upload.');
            return;
        }

        setUploading(true);
        setError(null);

        const formData = new FormData();
        formData.append('invoice_pdf', file);

        try {
            const response = await axios.post<InvoicePdfUploadResponse>(
                urls.upload,
                formData,
                {
                    headers: { 'Content-Type': 'multipart/form-data' },
                },
            );

            notifications.show({
                title: 'Invoice uploaded',
                message:
                    response.data.message ?? 'Invoice uploaded successfully.',
                color: 'green',
            });

            setOpened(false);
            setFile(null);
        } catch (caught) {
            if (axios.isAxiosError(caught) && caught.response?.status === 422) {
                setError('Upload a valid PDF file up to 20 MB.');
                return;
            }

            setError('The invoice could not be uploaded. Please try again.');
        } finally {
            setUploading(false);
        }
    };

    const button =
        display === 'button' ? (
            <Button
                leftIcon={<IconFileDollar size={16} />}
                variant="light"
                color="green"
                loading={checking}
                onClick={handleView}
            >
                {label}
            </Button>
        ) : (
            <Tooltip label={label} withArrow withinPortal>
                <ActionIcon
                    aria-label={label}
                    disabled={checking}
                    onClick={handleView}
                >
                    <IconFileDollar color="green" />
                </ActionIcon>
            </Tooltip>
        );

    return (
        <>
            {button}

            <Modal
                opened={opened}
                onClose={() => setOpened(false)}
                title="Upload invoice"
                centered
            >
                <Stack spacing="md">
                    <Text size="sm" color="dimmed">
                        {invoiceNo
                            ? `Invoice ${invoiceNo} is not available yet. Upload the PDF to view it.`
                            : 'This invoice PDF is not available yet. Upload the PDF to view it.'}
                    </Text>

                    <FileInput
                        label="Invoice PDF"
                        accept="application/pdf"
                        icon={<IconUpload size={16} />}
                        value={file}
                        onChange={(value) => {
                            setFile(value);
                            setError(null);
                        }}
                        error={error}
                    />

                    <Group position="right" spacing="sm">
                        <Button
                            variant="subtle"
                            onClick={() => setOpened(false)}
                            disabled={uploading}
                        >
                            Cancel
                        </Button>
                        <Button
                            leftIcon={<IconUpload size={16} />}
                            onClick={handleUpload}
                            loading={uploading}
                        >
                            Upload
                        </Button>
                    </Group>
                </Stack>
            </Modal>
        </>
    );
}
