<script setup lang="ts">
import { Head, usePage } from '@inertiajs/vue3';
import { computed, onMounted, ref, watch } from 'vue';
import { toast } from 'vue-sonner';
import CreateButton from '@/components/button/CreateButton.vue';
import ThermalPrinterConnectButton from '@/components/order/ThermalPrinterConnectButton.vue';
import { Card, CardContent } from '@/components/ui/card';
import { useCan } from '@/composables/useCan';
import {
    useDataTableQuery,
    useDataTableQuerySync,
} from '@/composables/useDataTableQuery';
import {
    getPaperSizeLabel,
    useThermalPrinter,
} from '@/composables/useThermalPrinter';
import { OrderChannel } from '@/constants/order-channel';
import { OrderPaymentType } from '@/constants/order-payment-type';
import { OrderStatus } from '@/constants/order-status';
import AdminLayout from '@/layouts/AdminLayout.vue';
import type { PaperSize } from '@/lib/thermal-printer/types';
import { index, create } from '@/routes/admin/manage/orders';
import type { DataTableFilterDef } from '@/types/data-table';
import type { PaginatedOrders } from '@/types/order';
import OrderGroupedTable from './table/OrderGroupedTable.vue';

const props = defineProps<{
    orders: PaginatedOrders;
    summary: {
        total_orders: number;
        total_amount: number;
        total_amount_formatted: string;
        total_subtotal: number;
        total_subtotal_formatted: string;
        total_discount: number;
        total_discount_formatted: string;
    };
    filters: {
        search: string;
        sort?: string;
        direction?: 'asc' | 'desc';
        channel?: string;
        status?: string;
        payment_type?: string;
        date_from?: string;
        date_to?: string;
    };
}>();

const { can } = useCan();
const page = usePage();
const { isConnected, printOrderReceipt, tryReconnect } = useThermalPrinter();
const search = ref(props.filters.search ?? '');

const { query, setSearch, setFilter, resetFilters, syncFromServer } = useDataTableQuery({
    url: index.url(),
    initial: { ...props.filters },
    filterKeys: ['channel', 'status', 'payment_type', 'date_from', 'date_to'],
});

useDataTableQuerySync(() => props.filters, syncFromServer);

const filterDefs = computed<DataTableFilterDef[]>(() => [
    {
        key: 'channel',
        label: 'Channel',
        type: 'select',
        options: [
            { value: OrderChannel.STORE, label: 'Toko' },
            { value: OrderChannel.SHOPEE, label: 'Shopee' },
            { value: OrderChannel.TIKTOK, label: 'TikTok' },
        ],
    },
    {
        key: 'status',
        label: 'Status',
        type: 'select',
        options: [
            { value: OrderStatus.PENDING, label: 'Menunggu' },
            { value: OrderStatus.PROCESSING, label: 'Diproses' },
            { value: OrderStatus.COMPLETED, label: 'Selesai' },
            { value: OrderStatus.CANCELLED, label: 'Dibatalkan' },
        ],
    },
    {
        key: 'payment_type',
        label: 'Tipe Pembayaran',
        type: 'select',
        options: [
            { value: OrderPaymentType.CASH, label: 'Cash' },
            { value: OrderPaymentType.TRANSFER, label: 'Transfer' },
            { value: OrderPaymentType.QRIS, label: 'QRIS' },
            { value: OrderPaymentType.MARKETPLACE, label: 'Marketplace' },
        ],
    },
    {
        key: 'date_from',
        label: 'Dari Tanggal',
        type: 'date',
    },
    {
        key: 'date_to',
        label: 'Sampai Tanggal',
        type: 'date',
    },
]);

const filterValues = computed(() => ({
    channel: query.value.channel ?? '',
    status: query.value.status ?? '',
    payment_type: query.value.payment_type ?? '',
    date_from: query.value.date_from ?? '',
    date_to: query.value.date_to ?? '',
}));

const tablePagination = computed(() => ({
    currentPage: props.orders.current_page,
    perPage: props.orders.per_page,
    lastPage: props.orders.last_page,
    total: props.orders.total,
}));

const firstItem = computed(() =>
    props.orders.data.length > 0
        ? (props.orders.current_page - 1) * props.orders.per_page + 1
        : 0,
);

watch(search, (value) => {
    setSearch(value);
});

watch(
    () => props.filters.search,
    (value) => {
        search.value = value ?? '';
    },
);

onMounted(async () => {
    const urlParams = new URLSearchParams(window.location.search);

    if (!urlParams.has('print') || props.orders.data.length === 0) {
        return;
    }

    const paperSize = (urlParams.get('paper_size') || '80mm') as PaperSize;
    const order = props.orders.data[0];

    window.history.replaceState({}, '', window.location.pathname);

    if (!isConnected.value) {
        const restored = await tryReconnect();

        if (!restored) {
            toast.error('Printer belum terhubung. Struk tidak dapat dicetak.');

            return;
        }
    }

    try {
        await printOrderReceipt({
            order,
            paperSize,
            storeName: page.props.name as string,
            storeAddress: (page.props.address as string) ?? '',
        });

        toast.success(
            `Struk ${order.order_number} dikirim ke printer ${getPaperSizeLabel(paperSize)}.`,
        );
    } catch (error) {
        const message =
            error instanceof Error
                ? error.message
                : 'Gagal mencetak struk pesanan.';

        toast.error(message);
    }
});
</script>

<template>
    <Head title="Pesanan" />

    <AdminLayout>
        <div
            class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"
        >
            <div class="space-y-1">
                <h2 class="text-2xl font-bold tracking-tight">Pesanan</h2>
            </div>

            <div
                class="flex shrink-0 items-center gap-2 self-start sm:self-center"
                v-if="can('orders.create')"
            >
                <ThermalPrinterConnectButton />

                <CreateButton :href="create.url()" />
            </div>
        </div>

        <Card class="min-w-0">
            <CardContent class="min-w-0">
                <OrderGroupedTable
                    v-model:search="search"
                    :orders="orders.data"
                    :summary="summary"
                    :first-item="firstItem"
                    :pagination="tablePagination"
                    :pagination-links="orders.links"
                    :filter-defs="filterDefs"
                    :filter-values="filterValues"
                    @filter-change="setFilter"
                    @filters-reset="resetFilters"
                />
            </CardContent>
        </Card>
    </AdminLayout>
</template>
