import { Button, Container, Flex, Heading, Slider, Text } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router"
import { Effect, SubscriptionRef } from "effect"
import { AsyncResult } from "effect/unstable/reactivity"
import { Component, Lens, Mutation, Query, View } from "effect-fc-next"
import { fetchPost, type Post } from "@/post"
import { runtime } from "@/runtime"


interface PostResultViewProps {
    readonly result: AsyncResult.AsyncResult<Post, Error>
}

const PostResultView = (props: PostResultViewProps) =>
    AsyncResult.match(props.result, {
        onInitial: () => <Text>Loading...</Text>,
        onFailure: () => <Text>Request failed.</Text>,
        onSuccess: result => (
            <>
                <Heading>{result.value.title}</Heading>
                <Text>{result.value.body}</Text>
            </>
        ),
    })

const QueryRouteComponent = Component.make("QueryRouteView")(function*() {
    const [idLens, query, mutation] = yield* Component.useOnMount(() => Effect.gen(function*() {
        const idLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(1))
        const query = yield* Query.service({
            key: idLens,
            f: fetchPost,
            staleTime: "10 seconds",
        })
        const mutation = yield* Mutation.make({
            f: fetchPost,
        })

        return [idLens, query, mutation] as const
    }))

    const [id] = yield* View.useAll([idLens])
    const [queryState, mutationResult] = yield* View.useAll([
        query.state,
        mutation.state,
    ])
    const runPromise = yield* Component.useRunPromise()

    return (
        <Container>
            <Flex direction="column" align="center" gap="2">
                <Slider
                    value={[id]}
                    min={1}
                    max={10}
                    onValueChange={([value]) =>
                        void runPromise(Lens.set(idLens, value ?? 1))
                    }
                />

                <PostResultView result={queryState.result} />

                <Flex direction="row" justify="center" align="center" gap="1">
                    <Button onClick={() => void runPromise(query.refresh)}>
                        Refresh
                    </Button>
                    <Button onClick={() => void runPromise(query.invalidateCache)}>
                        Invalidate cache
                    </Button>
                </Flex>

                <PostResultView result={mutationResult} />

                <Button onClick={() => void runPromise(mutation.mutate(id))}>
                    Mutate
                </Button>
            </Flex>
        </Container>
    )
}).pipe(
    Component.withRuntime(runtime.context),
)

export const Route = createFileRoute("/query")({
    component: QueryRouteComponent,
})
