import { Gtk } from "ags/gtk4";
import GLib from "gi://GLib";
import Gio from "gi://Gio";
import { watchFile } from "../../lib/fileMonitor";

// ---------------------------------------------------------------------------
// Thunderbird calendar database
// ---------------------------------------------------------------------------

const THUNDERBIRD_PROFILE = "tjle5dz0.default-release";

const DB_PATH = GLib.build_filenamev([
    GLib.get_home_dir(),
    ".thunderbird",
    THUNDERBIRD_PROFILE,
    "calendar-data",
    "local.sqlite",
]);

/**
 * Query the Thunderbird local.sqlite for distinct days (1-31) that have at
 * least one event in the given month.
 *
 * Thunderbird stores `event_start` / `event_end` as Unix timestamps in
 * **microseconds**, so we multiply JS millisecond timestamps by 1000.
 */
function queryEventDays(year: number, month: number): number[] {
    // month is 0-based (GTK Calendar convention)
    const monthStart = Date.UTC(year, month, 1) * 1000; // ms → μs
    const monthEnd   = Date.UTC(year, month + 1, 1) * 1000;

    const sql = [
        "SELECT DISTINCT",
        "  CAST(strftime('%d', event_start / 1000000, 'unixepoch') AS INTEGER) AS day",
        "FROM cal_events",
        `WHERE event_start >= ${monthStart}`,
        `  AND event_start <  ${monthEnd}`,
        "ORDER BY day;",
    ].join(" ");

    try {
        const proc = Gio.Subprocess.new(
            ["sqlite3", DB_PATH, sql],
            Gio.SubprocessFlags.STDOUT_PIPE |
                Gio.SubprocessFlags.STDERR_PIPE,
        );

        const [, stdout] = proc.communicate(null, null);
        if (!proc.get_successful()) return [];

        const output = new TextDecoder().decode(stdout);
        return output
            .trim()
            .split("\n")
            .filter((l) => l !== "")
            .map(Number);
    } catch (e) {
        console.error("Failed to query calendar events:", e);
        return [];
    }
}

// ---------------------------------------------------------------------------
// Clock helper
// ---------------------------------------------------------------------------

function formatTime(dt: GLib.DateTime): string {
    return dt.format("%H:%M:%S");
}

function formatDate(dt: GLib.DateTime): string {
    return dt.format("%d.%m. %a");
}

// ---------------------------------------------------------------------------
// Widget
// ---------------------------------------------------------------------------

export default function DateTime() {
    const root = new Gtk.Box({ cssClasses: ["datetime-bar"] });

    // -- Clock labels --

    const dateLabel = new Gtk.Label({
        cssClasses: ["clock-date"],
        halign: Gtk.Align.CENTER,
    });
    const timeLabel = new Gtk.Label({
        cssClasses: ["clock-time"],
        halign: Gtk.Align.CENTER,
    });

    const clockBox = new Gtk.Box({
        orientation: Gtk.Orientation.HORIZONTAL,
        halign: Gtk.Align.CENTER,
        valign: Gtk.Align.CENTER,
    });
    clockBox.append(dateLabel);
    clockBox.append(timeLabel);

    // -- Button that contains the clock --

    const button = new Gtk.Button({ cssClasses: ["datetime-btn"] });
    button.set_child(clockBox);
    root.append(button);

    // -- Calendar (inside popover) --

    const calendar = new Gtk.Calendar({
        vexpand: true,
        hexpand: true,
    });
    calendar.add_css_class("calendar-widget");

    function refreshMarks() {
        const y = calendar.get_year();
        const m = calendar.get_month(); // 0-11
        calendar.clear_marks();
        const days = queryEventDays(y, m);
        for (const d of days) {
            calendar.mark_day(d);
            
        }
    }

    // Re-fetch marks whenever the user navigates to a different month
    calendar.connect("next-month", refreshMarks);
    calendar.connect("prev-month", refreshMarks);
    calendar.connect("next-year", refreshMarks);
    calendar.connect("prev-year", refreshMarks);

    // -- Popover --

    const popover = new Gtk.Popover({
        autohide: true,
        has_arrow: true,
        cssClasses: ["calendar-popover"],
    });
    popover.set_parent(button);
    popover.set_child(calendar);

    button.connect("clicked", () => {
        if (popover.is_visible()) {
            popover.popdown();
        } else {
            refreshMarks(); // ensure fresh data on open
            popover.popup();
        }
    });

    // -- Clock timer (1 s) --

    let clockTimer = 0;

    function updateClock(): boolean {
        const now = GLib.DateTime.new_now_local();
        timeLabel.label = formatTime(now);
        dateLabel.label = formatDate(now);
        return GLib.SOURCE_CONTINUE;
    }

    updateClock(); // initial paint
    clockTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, updateClock);

    // -- Watch the SQLite DB for external changes (Thunderbird writes) --

    watchFile(DB_PATH, refreshMarks, root);

    // -- Initial event marks --

    refreshMarks();

    // -- Cleanup --

    root.connect("destroy", () => {
        if (clockTimer) GLib.Source.remove(clockTimer);
    });

    return root;
}
