import { WS_SCRCPY_URL } from "$lib/core/constants";
import type { Device } from "@pkg/logic/domains/device/data";
import { getDeviceByIdSQ } from "./device.remote";
import { toast } from "svelte-sonner";

type DeviceForUI = Omit<Device, "createdAt" | "updatedAt"> & {
    createdAt: Date | string;
    updatedAt: Date | string;
};

/** Port the scrcpy server listens on inside the Android container. */
const SCRCPY_SERVER_PORT = 8886;

/**
 * Builds the ws-scrcpy hash-based stream URL for a device.
 *
 * Example output:
 * https://iotam-ws-scrcpy.snapyra.com/#!action=stream&udid=172.17.0.1:5555
 *   &player=mse&ws=wss://iotam-ws-scrcpy.snapyra.com/?action=proxy-adb
 *   &remote=tcp:8886&udid=172.17.0.1:5555
 */
function buildStreamUrl(host: string, wsPort: string): string | null {
    const trimmedHost = host.trim();
    if (!trimmedHost) return null;

    const udid = `${trimmedHost}:${wsPort}`;
    const baseWss = WS_SCRCPY_URL.replace(/^https:/, "wss:").replace(/^http:/, "ws:");

    const wsParam =
        `${baseWss}/?action=proxy-adb&remote=${encodeURIComponent(`tcp:${SCRCPY_SERVER_PORT}`)}&udid=${encodeURIComponent(udid)}`;

    const hash =
        `#!action=stream&udid=${encodeURIComponent(udid)}&player=mse&ws=${encodeURIComponent(wsParam)}`;

    return `${WS_SCRCPY_URL}/${hash}`;
}

class DeviceDetailsViewModel {
    device = $state<DeviceForUI | null>(null);
    loading = $state(false);
    currentId = $state<number | null>(null);
    private _deviceQuery: ReturnType<typeof getDeviceByIdSQ> | null = null;

    get streamUrl(): string | null {
        if (!this.device) return null;
        return buildStreamUrl(this.device.host, this.device.wsPort);
    }

    async fetchDevice(id: number) {
        this.loading = true;
        this.currentId = id;

        try {
            const query = getDeviceByIdSQ({ id });

            if (query.ready) {
                await query.refresh();
            }

            const result = query.ready ? query.current : await query;
            this._deviceQuery = query;

            if (result?.error || !result?.data) {
                this.device = null;
                toast.error(result?.error?.message || "Failed to fetch device", {
                    description: result?.error?.description || "Please try again",
                });
                return;
            }

            this.device = result.data as DeviceForUI;
        } catch (error) {
            this.device = null;
            toast.error("Failed to fetch device", {
                description:
                    error instanceof Error ? error.message : "Please try again",
            });
        } finally {
            this.loading = false;
        }
    }
}

export const deviceDetailsVM = new DeviceDetailsViewModel();
