import { Gtk, Gdk } from "ags/gtk4";
import Adw from "gi://Adw";
import GLib from "gi://GLib";
import AstalNotifd from "gi://AstalNotifd";
import Pango from "gi://Pango";
import { timeout } from "ags/time";

function isIcon(icon?: string | null) {
    const iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!);
    return icon && iconTheme.has_icon(icon);
}

function fileExists(path: string) {
    return GLib.file_test(path, GLib.FileTest.EXISTS);
}

function time(time: number, format = "%H:%M") {
    return GLib.DateTime.new_from_unix_local(time).format(format)!;
}

function urgency(n: AstalNotifd.Notification) {
    const { LOW, NORMAL, CRITICAL } = AstalNotifd.Urgency;
    switch (n.urgency) {
        case LOW:
            return "low";
        case CRITICAL:
            return "critical";
        case NORMAL:
        default:
            return "normal";
    }
}

export default function Notification({
    notification: n,
    onHoverLost,
}: {
    notification: AstalNotifd.Notification;
    onHoverLost: () => void;
}) {
    const timer = timeout(3000, () => {
        try {
            onHoverLost();
        } catch (error) {
            console.error("Failed to handle onHoverLost:", error);
        }
    });

    const handleDismiss = () => {
        try {
            n.dismiss();
        } catch (error) {
            console.error("Failed to dismiss notification:", error);
        }
    };

    const handleInvoke = (id: string) => {
        try {
            n.invoke(id);
        } catch (error) {
            console.error(`Failed to invoke action ${id}:`, error);
        }
    };

    const handleTime = (timeValue: number) => {
        try {
            return time(timeValue);
        } catch (error) {
            console.error("Failed to format time:", error);
            return "Invalid time";
        }
    };

    return (
        <Adw.Clamp maximumSize={400}>
            <box
                widthRequest={400}
                class={`Notification ${urgency(n)}`}
                orientation={Gtk.Orientation.VERTICAL}
            >
                <Gtk.EventControllerMotion
                    onEnter={() => timer.cancel()}
                    onLeave={onHoverLost}
                />
                <box class="header">
                    {(n.appIcon || isIcon(n.desktopEntry)) && (
                        <image
                            class="app-icon"
                            visible={Boolean(n.appIcon || n.desktopEntry)}
                            iconName={n.appIcon || n.desktopEntry}
                        />
                    )}
                    <label
                        class="app-name"
                        halign={Gtk.Align.START}
                        ellipsize={Pango.EllipsizeMode.END}
                        label={n.appName || "Unknown"}
                    />
                    <label
                        class="time"
                        hexpand
                        halign={Gtk.Align.END}
                        label={handleTime(n.time)}
                    />
                    <button onClicked={handleDismiss}>
                        <image iconName="window-close-symbolic" />
                    </button>
                </box>
                <Gtk.Separator visible />
                <box class="content">
                    {n.image && fileExists(n.image) && (
                        <image valign={Gtk.Align.START} class="image" file={n.image} />
                    )}
                    {n.image && isIcon(n.image) && (
                        <box valign={Gtk.Align.START} class="icon-image">
                            <image
                                iconName={n.image}
                                halign={Gtk.Align.CENTER}
                                valign={Gtk.Align.CENTER}
                            />
                        </box>
                    )}
                    <box orientation={Gtk.Orientation.VERTICAL}>
                        <label
                            class="summary"
                            halign={Gtk.Align.START}
                            xalign={0}
                            label={n.summary}
                            ellipsize={Pango.EllipsizeMode.END}
                        />
                        {n.body && (
                            <label
                                class="body"
                                wrap
                                useMarkup
                                halign={Gtk.Align.START}
                                xalign={0}
                                justify={Gtk.Justification.FILL}
                                label={n.body}
                            />
                        )}
                    </box>
                </box>
                {n.actions.length > 0 && (
                    <box class="actions">
                        {n.actions.map(({ label, id }) => (
                            <button hexpand onClicked={() => handleInvoke(id)}>
                                <label label={label} halign={Gtk.Align.CENTER} hexpand />
                            </button>
                        ))}
                    </box>
                )}
            </box>
        </Adw.Clamp>
    );
}
