import type { ModifiedSession } from "@pkg/logic/domains/user/data";
import { authClient } from "$lib/auth.client";
import { toast } from "svelte-sonner";
import { ResultAsync, errAsync, okAsync } from "neverthrow";
import type { Err } from "@pkg/result";

class SessionsViewModel {
    session: ModifiedSession | undefined = $state(undefined);
    activeSessions = $state<ModifiedSession[]>([]);
    isLoading = $state(false);
    errorMessage = $state<string | null>(null);

    async setCurrentSession(s: ModifiedSession) {
        this.session = s;
    }

    async fetchActiveSessions() {
        this.isLoading = true;
        this.errorMessage = null;

        const result = await ResultAsync.fromPromise(
            authClient.listSessions(),
            (error): Err => ({
                code: "NETWORK_ERROR",
                message: "Failed to fetch active sessions",
                description: "Network request failed",
                detail: error instanceof Error ? error.message : String(error),
            }),
        )
            .andThen((response) => {
                if (response.error) {
                    return errAsync({
                        code: "API_ERROR",
                        message: "Failed to fetch active sessions",
                        description: response.error.message ?? "Unknown error",
                        detail: response.error.statusText ?? "Unknown error",
                    });
                }
                return okAsync(response.data ?? []);
            });

        const sessions = result.match(
            (data) => {
                this.activeSessions = data.map((session: ModifiedSession) => ({
                    ...session,
                    isCurrent: session.id === this.session?.id,
                }));
                return this.activeSessions;
            },
            (error) => {
                this.errorMessage = error.message ?? "Failed to fetch active sessions";
                toast.error("Failed to fetch active sessions", {
                    description: error.description,
                });
                return [];
            },
        );

        this.isLoading = false;
        return sessions;
    }

    async terminateSession(sessionId: string) {
        this.isLoading = true;
        this.errorMessage = null;

        const result = await ResultAsync.fromPromise(
            authClient.revokeSession({
                token: sessionId,
            }),
            (error): Err => ({
                code: "NETWORK_ERROR",
                message: "Failed to terminate session",
                description: "Network request failed",
                detail: error instanceof Error ? error.message : String(error),
            }),
        )
            .andThen((response) => {
                if (response.error) {
                    return errAsync({
                        code: "API_ERROR",
                        message: "Failed to terminate session",
                        description: response.error.message ?? "Unknown error",
                        detail: response.error.statusText ?? "Unknown error",
                    });
                }
                return okAsync(response.data);
            });

        result.match(
            () => {
                this.activeSessions = this.activeSessions.filter(
                    (session) => session.id !== sessionId,
                );
                toast.success("Session terminated");
            },
            (error) => {
                this.errorMessage = error.message ?? "Failed to terminate session";
                toast.error("Failed to terminate session", {
                    description: error.description,
                });
            },
        );

        this.isLoading = false;
    }

    async terminateAllOtherSessions() {
        this.isLoading = true;
        this.errorMessage = null;

        const result = await ResultAsync.fromPromise(
            authClient.revokeOtherSessions(),
            (error): Err => ({
                code: "NETWORK_ERROR",
                message: "Failed to terminate other sessions",
                description: "Network request failed",
                detail: error instanceof Error ? error.message : String(error),
            }),
        )
            .andThen((response) => {
                if (response.error) {
                    return errAsync({
                        code: "API_ERROR",
                        message: "Failed to terminate other sessions",
                        description: response.error.message ?? "Unknown error",
                        detail: response.error.statusText ?? "Unknown error",
                    });
                }
                return okAsync(response.data);
            });

        result.match(
            () => {
                this.activeSessions = this.activeSessions.filter(
                    // @ts-ignore
                    (session) => session.isCurrent,
                );
                toast.success("All other sessions terminated");
            },
            (error) => {
                this.errorMessage =
                    error.message ?? "Failed to terminate other sessions";
                toast.error("Failed to terminate other sessions", {
                    description: error.description,
                });
            },
        );

        this.isLoading = false;
    }

    async logout(skipToast = false) {
        const result = await ResultAsync.fromPromise(
            authClient.signOut(),
            (error): Err => ({
                code: "NETWORK_ERROR",
                message: "Failed to log out",
                description: "Network request failed",
                detail: error instanceof Error ? error.message : String(error),
            }),
        );

        result.match(
            () => {
                if (!skipToast) {
                    toast("Logged out successfully, redirecting...");
                }
                setTimeout(() => {
                    window.location.href = "/auth/login";
                }, 500);
            },
            (error) => {
                toast.error("Failed to log out", {
                    description: error.description,
                });
            },
        );
    }

    formatRelativeTime(timestamp: string | number): string {
        const date = new Date(timestamp);
        const now = new Date();
        const diffInSeconds = Math.floor(
            (now.getTime() - date.getTime()) / 1000,
        );

        if (diffInSeconds < 60) {
            return "just now";
        } else if (diffInSeconds < 3600) {
            const minutes = Math.floor(diffInSeconds / 60);
            return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
        } else if (diffInSeconds < 86400) {
            const hours = Math.floor(diffInSeconds / 3600);
            return `${hours} hour${hours > 1 ? "s" : ""} ago`;
        } else {
            const days = Math.floor(diffInSeconds / 86400);
            return `${days} day${days > 1 ? "s" : ""} ago`;
        }
    }

    reset() {
        this.activeSessions = [];
        this.isLoading = false;
        this.errorMessage = null;
    }
}

export const sessionsVM = new SessionsViewModel();
