/**
 * E2E Test Fixtures — FastAPI flavor.
 *
 * Mirrors examples/django-react-site/harness/src/fixtures.tsx minus the
 * Django-only surfaces (channels, forms). Each fixture uses GENERATED
 * mizan hooks (not raw call()). Playwright reads the DOM to verify
 * behavior. URL hash selects the fixture: #echo, #add, etc.
 */

import { useState, useEffect } from 'react'

import {
    MizanContext,
    MorphsContext,
    useEcho,
    useAdd,
    useMultiply,
    useWhoami,
    useStaffOnly,
    useSuperuserOnly,
    useVerifiedOnly,
    useNotImplementedFn,
    useBuggyFn,
    usePermissionCheckFn,
    useCurrentUser,
    useMorphGroups,
    useMorphLayers,
    useSetMorphValue,
    MizanError,
    useMizan,
} from './api'


export function Fixtures() {
    const [hash, setHash] = useState(window.location.hash.slice(1))

    useEffect(() => {
        const onHash = () => setHash(window.location.hash.slice(1))
        window.addEventListener('hashchange', onHash)
        return () => window.removeEventListener('hashchange', onHash)
    }, [])

    switch (hash) {
        case 'echo': return <Echo />
        case 'add': return <Add />
        case 'multiply': return <Multiply />
        case 'not-found': return <NotFound />
        case 'validation-error': return <ValidationError />
        case 'auth-required': return <AuthRequired />
        case 'staff-only': return <StaffOnly />
        case 'superuser-only': return <SuperuserOnly />
        case 'verified-only': return <VerifiedOnly />
        case 'not-implemented': return <NotImplemented />
        case 'internal-error': return <InternalError />
        case 'permission-error': return <PermissionError_ />
        case 'permission-success': return <PermissionSuccess />
        case 'context-current-user': return <ContextCurrentUser />
        case 'merge-morph': return <MergeMorph />
        default: return <div data-testid="ready">Harness ready. Set #hash.</div>
    }
}


function Result({ data, error }: { data?: unknown; error?: unknown }) {
    return (
        <>
            {data !== undefined && (
                <pre data-testid="result">{JSON.stringify(data)}</pre>
            )}
            {error !== undefined && error !== null && (
                <>
                    <div data-testid="error-type">
                        {error instanceof MizanError ? 'MizanError' : 'Error'}
                    </div>
                    <div data-testid="error-code">
                        {error instanceof MizanError ? error.code : ''}
                    </div>
                    <pre data-testid="error-message">
                        {error instanceof Error ? error.message : String(error)}
                    </pre>
                </>
            )}
        </>
    )
}


function useRun<T>(hook: () => { mutate: (input?: any) => Promise<T> }, input?: any) {
    const { mutate } = hook()
    const [data, setData] = useState<T>()
    const [error, setError] = useState<unknown>()

    useEffect(() => {
        mutate(input).then(setData).catch(setError)
    }, []) // eslint-disable-line react-hooks/exhaustive-deps

    return { data, error }
}


function Echo() { const r = useRun(useEcho, { text: 'e2e-test' }); return <Result {...r} /> }
function Add() { const r = useRun(useAdd, { a: 17, b: 25 }); return <Result {...r} /> }
function Multiply() { const r = useRun(useMultiply, { x: 6, y: 7 }); return <Result {...r} /> }

function NotFound() {
    const { call } = useMizan()
    const [error, setError] = useState<unknown>()
    useEffect(() => { call('does_not_exist').catch(setError) }, [call])
    return <Result error={error} />
}

function ValidationError() {
    const { mutate } = useAdd()
    const [error, setError] = useState<unknown>()
    useEffect(() => { (mutate as any)({ a: 'not_a_number', b: 'also_not' }).catch(setError) }, [mutate])
    return <Result error={error} />
}

function AuthRequired() { const r = useRun(useWhoami); return <Result {...r} /> }
function StaffOnly() { const r = useRun(useStaffOnly); return <Result {...r} /> }
function SuperuserOnly() { const r = useRun(useSuperuserOnly); return <Result {...r} /> }
function VerifiedOnly() { const r = useRun(useVerifiedOnly); return <Result {...r} /> }
function NotImplemented() { const r = useRun(useNotImplementedFn); return <Result {...r} /> }
function InternalError() { const r = useRun(useBuggyFn); return <Result {...r} /> }
function PermissionError_() { const r = useRun(usePermissionCheckFn, { secret: 'wrong' }); return <Result {...r} /> }
function PermissionSuccess() { const r = useRun(usePermissionCheckFn, { secret: 'open-sesame' }); return <Result {...r} /> }


function ContextCurrentUser() {
    try {
        const user = useCurrentUser()
        if (user === null) return <div>loading context...</div>
        return <pre data-testid="result">{JSON.stringify(user)}</pre>
    } catch {
        return <div>loading context...</div>
    }
}


function MergeMorph() {
    return (
        <MorphsContext>
            <MergeMorphInner />
        </MorphsContext>
    )
}

function MergeMorphInner() {
    const groups = useMorphGroups()
    const layers = useMorphLayers()
    const { mutate } = useSetMorphValue()
    const [fired, setFired] = useState(false)

    useEffect(() => {
        if (layers && groups && !fired) {
            setFired(true)
            mutate({ id: 1, value: 0.75 })
        }
    }, [layers, groups, fired, mutate])

    if (layers === null || groups === null) return <div>loading...</div>
    return <pre data-testid="result">{JSON.stringify({ groups, layers })}</pre>
}
