import { useEffect, useMemo, useState, type ReactNode } from "react";
import { Bell, CheckCheck, RefreshCw, Trash2, Zap } from "lucide-react";
import { useI18n } from "@/lib/i18n";
import { usePolledJson } from "@/hooks/use-polled-json";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Skeleton } from "@/components/ui/skeleton";
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

const EVENTS = [
    ["detected", "New signal"],
    ["entry_reached", "Entry reached"],
    ["target_hit", "Target reached"],
    ["invalidated", "Signal invalidated"],
] as const;

type SignalAlertEvent = (typeof EVENTS)[number][0];

type Preference = {
    id: number;
    symbol: string;
    provider: string;
    market: "spot" | "futures";
    interval: string;
    events: SignalAlertEvent[];
    enabled: boolean;
    telegram_chat_id?: string | null;
};

type Notification = {
    id: number;
    event: SignalAlertEvent;
    provider?: string;
    symbol?: string;
    market?: "spot" | "futures";
    interval?: string;
    title: string;
    message: string;
    read_at?: string | null;
    created_at: string;
};

type ProviderOption = {
    slug: string;
    name: string;
    markets: string[];
};

type SignalAlertPayload = {
    providers?: ProviderOption[];
    preferences?: Preference[];
    notifications?: Notification[];
    unread?: number;
};

export type WatchlistItem = {
    symbol: string;
    market: "spot" | "futures";
};

const EVENTS_LIST = EVENTS.map(([value]) => value);

const csrf = () =>
    document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") ?? "";

export default function SignalAlertPanel({ watchlist }: { watchlist: WatchlistItem[] }) {
    const { t } = useI18n();
    const alerts = usePolledJson<SignalAlertPayload>("/signal-alerts", 30000, true);
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState("");

    const preferences = alerts.data?.preferences ?? [];
    const notifications = alerts.data?.notifications ?? [];
    const unread = Number(alerts.data?.unread ?? 0);
    const initialWatchlistItem = watchlist.find((item) => item.market === "spot") ?? watchlist[0];

    const [form, setForm] = useState({
        symbol: initialWatchlistItem?.symbol ?? "",
        provider: "binance",
        market: initialWatchlistItem?.market ?? "spot",
        interval: "15m",
        events: EVENTS_LIST as SignalAlertEvent[],
        telegram_chat_id: "",
    });

    const marketWatchlist = useMemo(
        () => watchlist.filter((item) => item.market === form.market),
        [form.market, watchlist],
    );

    const providerOptions = useMemo(
        () =>
            (alerts.data?.providers ?? []).filter((provider) =>
                provider.markets.includes(form.market),
            ),
        [alerts.data?.providers, form.market],
    );

    useEffect(() => {
        if (providerOptions.length > 0 && !providerOptions.some((item) => item.slug === form.provider)) {
            setForm((current) => ({ ...current, provider: providerOptions[0].slug }));
        }
    }, [form.provider, providerOptions]);

    useEffect(() => {
        if (marketWatchlist.length > 0 && !marketWatchlist.some((item) => item.symbol === form.symbol)) {
            setForm((current) => ({ ...current, symbol: marketWatchlist[0].symbol }));
        }
    }, [form.symbol, marketWatchlist]);

    const performAction = async (
        url: string,
        method: "POST" | "PATCH" | "DELETE",
        body?: unknown,
    ) => {
        setBusy(true);
        setError("");

        try {
            const response = await fetch(url, {
                method,
                headers: {
                    Accept: "application/json",
                    "X-CSRF-TOKEN": csrf(),
                    ...(body === undefined ? {} : { "Content-Type": "application/json" }),
                },
                credentials: "same-origin",
                body: body === undefined ? undefined : JSON.stringify(body),
            });
            const payload = await response.json().catch(() => null);

            if (!response.ok) {
                throw new Error(
                    typeof payload?.message === "string"
                        ? payload.message
                        : `HTTP ${response.status}`,
                );
            }

            alerts.refetch();
            return true;
        } catch (reason) {
            setError(
                reason instanceof Error
                    ? reason.message
                    : t("Signal alert operation failed. Please try again."),
            );
            return false;
        } finally {
            setBusy(false);
        }
    };

    const create = async () => {
        if (form.events.length === 0) {
            setError(t("Select at least one notification event."));
            return;
        }

        await performAction("/signal-alerts", "POST", form);
    };

    const update = async (preference: Preference, patch: Partial<Preference>) => {
        await performAction(`/signal-alerts/${preference.id}`, "PATCH", patch);
    };

    const remove = async (id: number) => {
        await performAction(`/signal-alerts/${id}`, "DELETE");
    };

    const markRead = async (id: number) => {
        await performAction(`/signal-alerts/notifications/${id}/read`, "POST");
    };

    const markAllRead = async () => {
        await performAction("/signal-alerts/notifications/read-all", "POST");
    };

    const eventLabels = useMemo(() => new Map(EVENTS), []);

    return (
        <Card>
            <CardHeader className="pb-4">
                <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
                    <div>
                        <CardTitle className="flex items-center gap-2 text-base">
                            <Zap className="size-4 text-primary" />
                            {t("Signal Alerts")}
                        </CardTitle>
                        <CardDescription>
                            {t(
                                "Choose a market and the signal events you want to receive.",
                            )}
                        </CardDescription>
                    </div>
                    <Button
                        type="button"
                        size="icon"
                        variant="outline"
                        onClick={alerts.refetch}
                        disabled={alerts.loading}
                        aria-label={t("Refresh")}
                    >
                        <RefreshCw className={`size-4 ${alerts.loading ? "animate-spin" : ""}`} />
                    </Button>
                </div>
            </CardHeader>

            <CardContent className="space-y-6">
                {(error || alerts.error) && (
                    <Alert variant="destructive">
                        <Bell className="size-4" />
                        <AlertTitle>{t("Signal Alerts")}</AlertTitle>
                        <AlertDescription className="flex flex-wrap items-center justify-between gap-3">
                            <span>{error || alerts.error}</span>
                            {alerts.error && (
                                <Button
                                    type="button"
                                    size="sm"
                                    variant="outline"
                                    onClick={alerts.refetch}
                                    disabled={alerts.loading}
                                >
                                    {t("Try again")}
                                </Button>
                            )}
                        </AlertDescription>
                    </Alert>
                )}

                <div className="rounded-lg border bg-muted/20 p-4">
                    <div className="mb-4 flex items-center justify-between gap-3">
                        <div>
                            <p className="text-sm font-medium">{t("Create signal rule")}</p>
                            <p className="text-xs text-muted-foreground">
                                {t("One rule can watch a symbol across the selected market and timeframe.")}
                            </p>
                        </div>
                        <Badge variant="secondary">
                            {form.events.length} {t("events")}
                        </Badge>
                    </div>

                    {alerts.loading && !alerts.data ? (
                        <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
                            {[1, 2, 3, 4].map((item) => (
                                <Skeleton key={item} className="h-10 w-full" />
                            ))}
                        </div>
                    ) : (
                        <>
                            <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
                                <Field label={t("Market")}>
                                    <Select
                                        value={form.market}
                                        onValueChange={(value) =>
                                            setForm((current) => {
                                                const market: "spot" | "futures" =
                                                    value === "futures" ? "futures" : "spot";
                                                const nextProviders = (alerts.data?.providers ?? []).filter((provider) =>
                                                    provider.markets.includes(market),
                                                );
                                                const provider = nextProviders.some((item) => item.slug === current.provider)
                                                    ? current.provider
                                                    : (nextProviders[0]?.slug ?? "binance");
                                                const nextWatchlistItem = watchlist.find((item) => item.market === market);
                                                return {
                                                    ...current,
                                                    market,
                                                    provider,
                                                    symbol: nextWatchlistItem?.symbol ?? "",
                                                };
                                            })
                                        }
                                    >
                                        <SelectTrigger>
                                            <SelectValue />
                                        </SelectTrigger>
                                        <SelectContent>
                                            <SelectItem value="spot">{t("Spot")}</SelectItem>
                                            <SelectItem value="futures">{t("Futures")}</SelectItem>
                                        </SelectContent>
                                    </Select>
                                </Field>

                                <Field label={t("Symbol")}>
                                    <Select
                                        value={form.symbol ? `${form.market}:${form.symbol}` : undefined}
                                        onValueChange={(value) => {
                                            const [, symbol] = value.split(":");
                                            setForm((current) => ({ ...current, symbol }));
                                        }}
                                        disabled={marketWatchlist.length === 0}
                                    >
                                        <SelectTrigger>
                                            <SelectValue placeholder={t("Select a symbol")} />
                                        </SelectTrigger>
                                        <SelectContent>
                                            {marketWatchlist.map((item) => (
                                                <SelectItem
                                                    key={`${item.market}:${item.symbol}`}
                                                    value={`${item.market}:${item.symbol}`}
                                                >
                                                    {item.symbol}
                                                </SelectItem>
                                            ))}
                                        </SelectContent>
                                    </Select>
                                </Field>

                                <Field label={t("Provider")}>
                                    <Select
                                        value={form.provider}
                                        onValueChange={(value) => setForm((current) => ({ ...current, provider: value }))}
                                        disabled={providerOptions.length === 0}
                                    >
                                        <SelectTrigger>
                                            <SelectValue placeholder={t("Provider")} />
                                        </SelectTrigger>
                                        <SelectContent>
                                            {providerOptions.map((provider) => (
                                                <SelectItem key={provider.slug} value={provider.slug}>
                                                    {provider.name}
                                                </SelectItem>
                                            ))}
                                        </SelectContent>
                                    </Select>
                                </Field>

                                <Field label={t("Timeframe")}>
                                    <Select
                                        value={form.interval}
                                        onValueChange={(value) => setForm((current) => ({ ...current, interval: value }))}
                                    >
                                        <SelectTrigger>
                                            <SelectValue />
                                        </SelectTrigger>
                                        <SelectContent>
                                            {["5m", "15m", "1h", "4h"].map((value) => (
                                                <SelectItem key={value} value={value}>
                                                    {value}
                                                </SelectItem>
                                            ))}
                                        </SelectContent>
                                    </Select>
                                </Field>
                            </div>

                            <div className="mt-4 space-y-3">
                                <Label className="text-sm">{t("Notify me when")}</Label>
                                <div className="grid gap-2 sm:grid-cols-2">
                                    {EVENTS.map(([value, label]) => {
                                        const checked = form.events.includes(value);
                                        return (
                                            <label
                                                key={value}
                                                className="flex cursor-pointer items-start gap-3 rounded-md border bg-background p-3"
                                            >
                                                <Checkbox
                                                    checked={checked}
                                                    onCheckedChange={(next) =>
                                                        setForm((current) => ({
                                                            ...current,
                                                            events:
                                                                next === true
                                                                    ? [...current.events, value]
                                                                    : current.events.filter((event) => event !== value),
                                                        }))
                                                    }
                                                    className="mt-0.5"
                                                />
                                                <span>
                                                    <span className="block text-sm font-medium">{t(label)}</span>
                                                    <span className="block text-xs text-muted-foreground">
                                                        {t(eventDescription(value))}
                                                    </span>
                                                </span>
                                            </label>
                                        );
                                    })}
                                </div>
                            </div>

                            <div className="mt-4 grid gap-4 md:grid-cols-[1fr_auto]">
                                <Field label={t("Telegram Chat ID")} optional>
                                    <Input
                                        value={form.telegram_chat_id}
                                        onChange={(event) =>
                                            setForm((current) => ({
                                                ...current,
                                                telegram_chat_id: event.target.value,
                                            }))
                                        }
                                        placeholder={t("Optional")}
                                    />
                                </Field>
                                <div className="flex items-end">
                                    <Button
                                        type="button"
                                        onClick={() => void create()}
                                        disabled={
                                            busy ||
                                            alerts.loading ||
                                            !form.symbol ||
                                            marketWatchlist.length === 0 ||
                                            form.events.length === 0
                                        }
                                        className="w-full md:w-auto"
                                    >
                                        {busy ? t("Saving…") : t("Create rule")}
                                    </Button>
                                </div>
                            </div>
                        </>
                    )}
                </div>

                <Tabs defaultValue="rules" className="w-full">
                    <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                        <TabsList className="w-full sm:w-[300px]">
                            <TabsTrigger value="rules">{t("Rules")} ({preferences.length})</TabsTrigger>
                            <TabsTrigger value="notifications">
                                {t("Notifications")} {unread > 0 ? `(${unread})` : ""}
                            </TabsTrigger>
                        </TabsList>
                        {unread > 0 && (
                            <Button
                                type="button"
                                size="sm"
                                variant="outline"
                                onClick={() => void markAllRead()}
                                disabled={busy}
                            >
                                <CheckCheck className="mr-2 size-4" />
                                {t("Mark all read")}
                            </Button>
                        )}
                    </div>

                    <TabsContent value="rules" className="mt-4">
                        {preferences.length === 0 ? (
                            <EmptyState text={t("No signal alert rules yet. Create your first rule above.")} />
                        ) : (
                            <div className="divide-y rounded-lg border">
                                {preferences.map((preference) => (
                                    <div
                                        key={preference.id}
                                        className="flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between"
                                    >
                                        <div className="min-w-0">
                                            <div className="flex flex-wrap items-center gap-2">
                                                <span className="font-semibold">
                                                    {preference.symbol}
                                                </span>
                                                <Badge variant="outline">{preference.market}</Badge>
                                                <Badge variant="outline">{preference.interval}</Badge>
                                                <Badge variant={preference.enabled ? "default" : "secondary"}>
                                                    {preference.enabled ? t("Enabled") : t("Disabled")}
                                                </Badge>
                                            </div>
                                            <p className="mt-1 text-xs text-muted-foreground">
                                                {preference.provider.toUpperCase()} · {preference.events
                                                    .map((event) => t(eventLabels.get(event) ?? event))
                                                    .join(" · ")}
                                            </p>
                                        </div>
                                        <div className="flex items-center gap-2">
                                            <Button
                                                type="button"
                                                size="sm"
                                                variant="outline"
                                                onClick={() =>
                                                    void update(preference, {
                                                        enabled: !preference.enabled,
                                                    })
                                                }
                                                disabled={busy}
                                            >
                                                {preference.enabled ? t("Disable") : t("Enable")}
                                            </Button>
                                            <Button
                                                type="button"
                                                size="icon"
                                                variant="ghost"
                                                onClick={() => void remove(preference.id)}
                                                disabled={busy}
                                                aria-label={t("Delete rule")}
                                            >
                                                <Trash2 className="size-4 text-destructive" />
                                            </Button>
                                        </div>
                                    </div>
                                ))}
                            </div>
                        )}
                    </TabsContent>

                    <TabsContent value="notifications" className="mt-4">
                        {notifications.length === 0 ? (
                            <EmptyState text={t("No signal notifications yet.")} />
                        ) : (
                            <div className="divide-y rounded-lg border">
                                {notifications.map((notification) => (
                                    <button
                                        key={notification.id}
                                        type="button"
                                        className="w-full p-4 text-left transition hover:bg-muted/30 disabled:cursor-default"
                                        onClick={() =>
                                            !notification.read_at && void markRead(notification.id)
                                        }
                                        disabled={busy || Boolean(notification.read_at)}
                                    >
                                        <div className="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
                                            <div className="flex items-center gap-2">
                                                {!notification.read_at && (
                                                    <span className="size-2 rounded-full bg-primary" aria-hidden />
                                                )}
                                                <span className="text-sm font-medium">
                                                    {notification.title}
                                                </span>
                                            </div>
                                            <span className="text-[11px] text-muted-foreground">
                                                {new Date(notification.created_at).toLocaleString()}
                                            </span>
                                        </div>
                                        <p className="mt-1 text-sm text-muted-foreground">
                                            {notification.message}
                                        </p>
                                        {(notification.provider || notification.symbol) && (
                                            <div className="mt-2 flex flex-wrap gap-1.5">
                                                {[notification.provider, notification.market, notification.symbol, notification.interval]
                                                    .filter(Boolean)
                                                    .map((value) => (
                                                        <Badge key={value} variant="secondary" className="font-normal">
                                                            {value}
                                                        </Badge>
                                                    ))}
                                            </div>
                                        )}
                                    </button>
                                ))}
                            </div>
                        )}
                    </TabsContent>
                </Tabs>
            </CardContent>
        </Card>
    );
}

function Field({
    label,
    optional = false,
    children,
}: {
    label: string;
    optional?: boolean;
    children: ReactNode;
}) {
    return (
        <div className="space-y-2">
            <div className="flex items-center justify-between gap-2">
                <Label className="text-sm">{label}</Label>
                {optional && <span className="text-[11px] text-muted-foreground">Optional</span>}
            </div>
            {children}
        </div>
    );
}

function EmptyState({ text }: { text: string }) {
    return (
        <div className="flex min-h-36 items-center justify-center rounded-lg border border-dashed px-6 text-center text-sm text-muted-foreground">
            {text}
        </div>
    );
}

function eventDescription(event: SignalAlertEvent) {
    switch (event) {
        case "detected":
            return "A new signal is detected.";
        case "entry_reached":
            return "Price reaches the current entry level.";
        case "target_hit":
            return "The tracked target level is reached.";
        case "invalidated":
            return "The current signal becomes invalid.";
    }
}
