import { getLinkController } from "@pkg/logic/domains/link/controller";
import { createLinkSchema, updateLinkSchema } from "@pkg/logic/domains/link/data";
import { getDeviceController } from "@pkg/logic/domains/device/controller";
import { getFlowExecCtxForRemoteFuncs, unauthorized } from "$lib/core/server.utils";
import { command, getRequestEvent, query } from "$app/server";
import * as v from "valibot";

const lc = getLinkController();
const dc = getDeviceController();

export const listLinksSQ = query(async () => {
    const event = getRequestEvent();
    const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
    if (!fctx.userId) return unauthorized(fctx);

    const res = await lc.list(fctx);
    return res.isOk()
        ? { data: res.value, error: null }
        : { data: null, error: res.error };
});

export const getLinkByIdSQ = query(
    v.object({ id: v.number() }),
    async (input) => {
        const event = getRequestEvent();
        const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
        if (!fctx.userId) return unauthorized(fctx);

        const res = await lc.getById(fctx, input.id);
        return res.isOk()
            ? { data: res.value, error: null }
            : { data: null, error: res.error };
    },
);

export const createLinkSC = command(
    v.omit(createLinkSchema, ["token"]),
    async (payload) => {
        const event = getRequestEvent();
        const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
        if (!fctx.userId) return unauthorized(fctx);

        const res = await lc.create(fctx, payload);
        return res.isOk()
            ? { data: res.value, error: null }
            : { data: null, error: res.error };
    },
);

export const updateLinkSC = command(
    v.object({ id: v.number(), data: updateLinkSchema }),
    async (payload) => {
        const event = getRequestEvent();
        const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
        if (!fctx.userId) return unauthorized(fctx);

        const res = await lc.update(fctx, payload.id, payload.data);
        return res.isOk()
            ? { data: res.value, error: null }
            : { data: null, error: res.error };
    },
);

export const revokeLinkSC = command(
    v.object({ id: v.number() }),
    async (payload) => {
        const event = getRequestEvent();
        const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
        if (!fctx.userId) return unauthorized(fctx);

        const linkResult = await lc.getById(fctx, payload.id);
        if (linkResult.isErr()) {
            return { data: null, error: linkResult.error };
        }

        const revokeResult = await lc.revoke(fctx, payload.id);
        if (revokeResult.isErr()) {
            return { data: null, error: revokeResult.error };
        }

        const linkedDeviceId = linkResult.value.linkedDeviceId;
        if (linkedDeviceId !== null) {
            const releaseResult = await dc.release(fctx, linkedDeviceId);
            if (releaseResult.isErr()) {
                return { data: null, error: releaseResult.error };
            }
        }

        return { data: revokeResult.value, error: null };
    },
);

export const deleteLinkSC = command(
    v.object({ id: v.number() }),
    async (payload) => {
        const event = getRequestEvent();
        const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
        if (!fctx.userId) return unauthorized(fctx);

        const res = await lc.delete(fctx, payload.id);
        return res.isOk()
            ? { data: res.value, error: null }
            : { data: null, error: res.error };
    },
);

export const assignDeviceSC = command(
    v.object({
        id: v.number(),
        deviceId: v.nullable(v.number()),
    }),
    async (payload) => {
        const event = getRequestEvent();
        const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
        if (!fctx.userId) return unauthorized(fctx);

        const res = await lc.assignDevice(fctx, payload.id, payload.deviceId);
        return res.isOk()
            ? { data: res.value, error: null }
            : { data: null, error: res.error };
    },
);
